diff options
author | Dave Roth <davidroth@google.com> | 2023-11-08 00:42:03 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-11-08 00:42:03 +0000 |
commit | e2c73889399ce97f00d56bd5b2e742888a8db69e (patch) | |
tree | 64d4651266cfc4887eaffe3ae159edc30f8a8abd | |
parent | 53027c0a50b85feb8815d1dc67349da8975fb67d (diff) | |
download | pigweed-e2c73889399ce97f00d56bd5b2e742888a8db69e.tar.gz |
pw_trace_tokenized: Add a transfer based trace service
Change-Id: Idac3ae2726d7ba081771bb672159c68c3467683b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168833
Commit-Queue: Dave Roth <davidroth@google.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
-rw-r--r-- | pw_trace_tokenized/BUILD.bazel | 67 | ||||
-rw-r--r-- | pw_trace_tokenized/BUILD.gn | 49 | ||||
-rw-r--r-- | pw_trace_tokenized/CMakeLists.txt | 26 | ||||
-rw-r--r-- | pw_trace_tokenized/base_trace_service.cc | 76 | ||||
-rw-r--r-- | pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h | 43 | ||||
-rw-r--r-- | pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h | 38 | ||||
-rw-r--r-- | pw_trace_tokenized/pw_trace_protos/trace_rpc.proto | 4 | ||||
-rw-r--r-- | pw_trace_tokenized/pw_trace_protos/trace_service.options | 13 | ||||
-rw-r--r-- | pw_trace_tokenized/pw_trace_protos/trace_service.proto | 53 | ||||
-rw-r--r-- | pw_trace_tokenized/py/BUILD.gn | 11 | ||||
-rw-r--r-- | pw_trace_tokenized/py/pyproject.toml | 16 | ||||
-rw-r--r-- | pw_trace_tokenized/py/setup.cfg | 29 | ||||
-rw-r--r-- | pw_trace_tokenized/trace_service_pwpb.cc | 75 | ||||
-rw-r--r-- | pw_trace_tokenized/trace_service_pwpb_test.cc | 130 |
14 files changed, 579 insertions, 51 deletions
diff --git a/pw_trace_tokenized/BUILD.bazel b/pw_trace_tokenized/BUILD.bazel index 4263ef3ef..6e76328e9 100644 --- a/pw_trace_tokenized/BUILD.bazel +++ b/pw_trace_tokenized/BUILD.bazel @@ -18,6 +18,7 @@ load( "pw_cc_library", "pw_cc_test", ) +load("//pw_build/bazel_internal:py_proto_library.bzl", "py_proto_library") load("//pw_protobuf_compiler:pw_proto_library.bzl", "pw_proto_library") package(default_visibility = ["//visibility:public"]) @@ -58,6 +59,43 @@ pw_cc_library( ) pw_cc_library( + name = "base_trace_service", + srcs = [ + "base_trace_service.cc", + ], + hdrs = [ + "public/pw_trace_tokenized/base_trace_service.h", + ], + includes = [ + "public", + ], + deps = [ + ":buffer", + ":pw_trace_tokenized", + "//pw_ring_buffer", + "//pw_stream", + ], +) + +pw_cc_library( + name = "trace_service_pwpb", + srcs = [ + "trace_service_pwpb.cc", + ], + hdrs = [ + "public/pw_trace_tokenized/trace_service_pwpb.h", + ], + includes = [ + "public", + ], + deps = [ + ":base_trace_service", + ":protos_cc.pwpb_rpc", + "//pw_chrono:system_clock", + ], +) + +pw_cc_library( name = "trace_rpc_service", srcs = [ "trace_rpc_service_nanopb.cc", @@ -121,10 +159,14 @@ proto_library( srcs = [ "pw_trace_protos/trace.proto", "pw_trace_protos/trace_rpc.proto", + "pw_trace_protos/trace_service.proto", + ], + deps = [ + "//pw_chrono:chrono_proto", ], # TODO(tpudlik): We should provide trace_rpc.options to nanopb here, but the # current proto codegen implementation provides no mechanism for doing so. - # inputs = [ "pw_trace_protos/trace_rpc.options" ] + # inputs = [ "pw_trace_protos/trace_rpc.options", "pw_trace_protos/trace_service.options"] ) pw_proto_library( @@ -132,6 +174,13 @@ pw_proto_library( deps = [":protos"], ) +py_proto_library( + name = "proto_py", + # TODO(b/241456982): Get this target to build. + tags = ["manual"], + deps = [":protos"], +) + pw_cc_library( name = "pw_trace_tokenized_fake_time", srcs = [ @@ -190,6 +239,22 @@ pw_cc_test( ], ) +pw_cc_test( + name = "trace_service_pwpb_test", + srcs = [ + "trace_service_pwpb_test.cc", + ], + # TODO(b/260641850): Get pw_trace_tokenized building in Bazel. + tags = ["manual"], + deps = [ + ":pw_trace_host_trace_time", + ":trace_service_pwpb", + "//pw_chrono:system_clock", + "//pw_rpc/pwpb:test_method_context", + "//pw_trace", + ], +) + pw_cc_library( name = "pw_trace_host_trace_time", srcs = ["host_trace_time.cc"], diff --git a/pw_trace_tokenized/BUILD.gn b/pw_trace_tokenized/BUILD.gn index 0e7be3121..c2c928e91 100644 --- a/pw_trace_tokenized/BUILD.gn +++ b/pw_trace_tokenized/BUILD.gn @@ -62,6 +62,7 @@ pw_test_group("tests") { ":trace_tokenized_test", ":tokenized_trace_buffer_test", ":tokenized_trace_buffer_log_test", + ":trace_service_pwpb_test", ] } @@ -101,8 +102,14 @@ pw_proto_library("protos") { sources = [ "pw_trace_protos/trace.proto", "pw_trace_protos/trace_rpc.proto", + "pw_trace_protos/trace_service.proto", ] - inputs = [ "pw_trace_protos/trace_rpc.options" ] + inputs = [ + "pw_trace_protos/trace_rpc.options", + "pw_trace_protos/trace_service.options", + ] + python_package = "py" + deps = [ "$dir_pw_chrono:protos" ] } pw_source_set("trace_rpc_service") { @@ -120,6 +127,46 @@ pw_source_set("trace_rpc_service") { ] } +pw_source_set("base_trace_service") { + public_configs = [ ":public_include_path" ] + public_deps = [ + ":core", + ":tokenized_trace_buffer", + ] + deps = [ + "$dir_pw_ring_buffer", + "$dir_pw_stream", + ] + sources = [ + "base_trace_service.cc", + "public/pw_trace_tokenized/base_trace_service.h", + ] +} + +pw_source_set("trace_service_pwpb") { + public_configs = [ ":public_include_path" ] + public_deps = [ + ":base_trace_service", + ":protos.pwpb_rpc", + ] + deps = [ "$dir_pw_chrono:system_clock" ] + sources = [ + "public/pw_trace_tokenized/trace_service_pwpb.h", + "trace_service_pwpb.cc", + ] +} + +pw_test("trace_service_pwpb_test") { + enable_if = _pw_trace_tokenized_is_selected + deps = [ + ":trace_service_pwpb", + "$dir_pw_chrono:system_clock", + "$dir_pw_rpc/pwpb:test_method_context", + "$dir_pw_trace", + ] + sources = [ "trace_service_pwpb_test.cc" ] +} + pw_source_set("tokenized_trace_buffer") { deps = [ ":core" ] public_deps = [ diff --git a/pw_trace_tokenized/CMakeLists.txt b/pw_trace_tokenized/CMakeLists.txt index e8780f6a4..bc6268f90 100644 --- a/pw_trace_tokenized/CMakeLists.txt +++ b/pw_trace_tokenized/CMakeLists.txt @@ -69,8 +69,12 @@ pw_add_library(pw_trace_tokenized.trace_buffer STATIC pw_proto_library(pw_trace_tokenized.protos SOURCES pw_trace_protos/trace_rpc.proto + pw_trace_protos/trace_service.proto INPUTS pw_trace_protos/trace_rpc.options + pw_trace_protos/trace_service.options + DEPS + pw_chrono.protos ) pw_add_library(pw_trace_tokenized.rpc_service STATIC @@ -87,3 +91,25 @@ pw_add_library(pw_trace_tokenized.rpc_service STATIC pw_tokenizer pw_status ) + +pw_add_library(pw_trace_tokenized.base_trace_service STATIC + SOURCES + base_trace_service.cc + PRIVATE_DEPS + pw_log + pw_stream + pw_ring_buffer + PUBLIC_DEPS + pw_trace_tokenized + pw_trace_tokenized.trace_buffer +) + +pw_add_library(pw_trace_tokenized.trace_service_pwpb STATIC + SOURCES + trace_service_pwpb.cc + PRIVATE_DEPS + pw_chrono.system_clock + PUBLIC_DEPS + pw_trace_tokenized.base_trace_service + pw_trace_tokenized.protos.pwpb_rpc +) diff --git a/pw_trace_tokenized/base_trace_service.cc b/pw_trace_tokenized/base_trace_service.cc new file mode 100644 index 000000000..56331f377 --- /dev/null +++ b/pw_trace_tokenized/base_trace_service.cc @@ -0,0 +1,76 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pw_trace_tokenized/base_trace_service.h" + +#include "pw_log/log.h" +#include "pw_trace_tokenized/trace_buffer.h" + +namespace pw::trace { +BaseTraceService::BaseTraceService(TokenizedTracer& tokenized_tracer, + stream::Writer& trace_writer) + : tokenized_tracer_(tokenized_tracer), trace_writer_(trace_writer) { + tokenized_tracer_.Enable(false); +} + +Status BaseTraceService::Start() { + PW_LOG_INFO("Starting Tracing"); + + if (tokenized_tracer_.IsEnabled()) { + PW_LOG_INFO("Tracing already started"); + return Status::FailedPrecondition(); + } + + tokenized_tracer_.Enable(true); + + return OkStatus(); +} + +Status BaseTraceService::Stop() { + PW_LOG_INFO("Stopping Tracing"); + + if (!tokenized_tracer_.IsEnabled()) { + PW_LOG_INFO("Tracing not started"); + return Status::FailedPrecondition(); + } + + tokenized_tracer_.Enable(false); + + auto ring_buffer = trace::GetBuffer(); + + if (ring_buffer->EntryCount() == 0) { + PW_LOG_WARN("EntryCount(%zu)", ring_buffer->EntryCount()); + return Status::Unavailable(); + } else if (ring_buffer->CheckForCorruption() != OkStatus()) { + PW_LOG_ERROR("EntryCount(%zu), Corruption(%d)", + ring_buffer->EntryCount(), + ring_buffer->CheckForCorruption().code()); + return Status::Unavailable(); + } + + PW_LOG_INFO("EntryCount(%zu)", ring_buffer->EntryCount()); + + ConstByteSpan inner_trace_span = trace::DeringAndViewRawBuffer(); + if (auto status = trace_writer_.Write(inner_trace_span); + status != OkStatus()) { + PW_LOG_ERROR("Failed to write trace data: %d)", status.code()); + return status; + } + + ring_buffer->Clear(); + + return OkStatus(); +} + +} // namespace pw::trace diff --git a/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h b/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h new file mode 100644 index 000000000..d6f219a36 --- /dev/null +++ b/pw_trace_tokenized/public/pw_trace_tokenized/base_trace_service.h @@ -0,0 +1,43 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include <cstdint> +#include <optional> + +#include "pw_status/status.h" +#include "pw_stream/stream.h" +#include "pw_trace_tokenized/trace_tokenized.h" + +namespace pw::trace { +class BaseTraceService { + public: + BaseTraceService(TokenizedTracer& tokenized_tracer, + stream::Writer& trace_writer); + + void SetTransferId(uint32_t id) { transfer_id_ = id; } + + protected: + Status Start(); + Status Stop(); + + private: + TokenizedTracer& tokenized_tracer_; + stream::Writer& trace_writer_; + + protected: + std::optional<uint32_t> transfer_id_; +}; + +} // namespace pw::trace diff --git a/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h b/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h new file mode 100644 index 000000000..c915dfb34 --- /dev/null +++ b/pw_trace_tokenized/public/pw_trace_tokenized/trace_service_pwpb.h @@ -0,0 +1,38 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "pw_trace_protos/trace_service.rpc.pwpb.h" +#include "pw_trace_tokenized/base_trace_service.h" + +namespace pw::trace { + +class TraceService final + : public proto::pw_rpc::pwpb::TraceService::Service<TraceService>, + public BaseTraceService { + public: + TraceService(TokenizedTracer& tokenized_tracer, stream::Writer& trace_writer); + + Status Start(const proto::pwpb::StartRequest::Message& request, + proto::pwpb::StartResponse::Message& response); + + Status Stop(const proto::pwpb::StopRequest::Message& request, + proto::pwpb::StopResponse::Message& response); + + Status GetClockParameters( + const proto::pwpb::ClockParametersRequest::Message& request, + proto::pwpb::ClockParametersResponse::Message& response); +}; + +} // namespace pw::trace diff --git a/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto b/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto index 39971e7c3..2b9b3bc28 100644 --- a/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto +++ b/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto @@ -15,6 +15,10 @@ syntax = "proto3"; package pw.trace; +// TODO: b/309643763 - This service has been deprecated in favor of the tracing +// service defined in trace_service.proto +// This service will be deleted once existing clients have been migrated awaw +// from it, so please don't use this for any new projects. service TraceService { rpc Enable(TraceEnableMessage) returns (TraceEnableMessage) {} rpc IsEnabled(Empty) returns (TraceEnableMessage) {} diff --git a/pw_trace_tokenized/pw_trace_protos/trace_service.options b/pw_trace_tokenized/pw_trace_protos/trace_service.options new file mode 100644 index 000000000..714d9397f --- /dev/null +++ b/pw_trace_tokenized/pw_trace_protos/trace_service.options @@ -0,0 +1,13 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. diff --git a/pw_trace_tokenized/pw_trace_protos/trace_service.proto b/pw_trace_tokenized/pw_trace_protos/trace_service.proto new file mode 100644 index 000000000..62be6fe9b --- /dev/null +++ b/pw_trace_tokenized/pw_trace_protos/trace_service.proto @@ -0,0 +1,53 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +syntax = "proto3"; + +package pw.trace.proto; + +import "pw_chrono_protos/chrono.proto"; + +// TODO: b/309643763 - This is the prefered service for tracing, and the service +// defined in trace_rpc.proto has been deprecated and will be removed once +// existings clients migrate to this service. +service TraceService { + // Start will enable tracing, populating the trace ring buffer. + rpc Start(StartRequest) returns (StartResponse) {} + + // On stop the ring buffer will be written to the configured + // stream. No data is written to the stream until Stop is called. + rpc Stop(StopRequest) returns (StopResponse) {} + + // Returns the clock paramaters of the system. + rpc GetClockParameters(ClockParametersRequest) + returns (ClockParametersResponse) {} +} + +message StartRequest {} + +message StartResponse {} + +message StopRequest {} + +message StopResponse { + // as a convenience, the file id is returned on stop which can be + // used to start a transfer directly, rather that requiring a user + // list the files to obtain the file id. + optional uint32 file_id = 1; +} + +message ClockParametersRequest {} + +message ClockParametersResponse { + pw.chrono.ClockParameters clock_parameters = 1; +} diff --git a/pw_trace_tokenized/py/BUILD.gn b/pw_trace_tokenized/py/BUILD.gn index 78c7f998d..4ad26412b 100644 --- a/pw_trace_tokenized/py/BUILD.gn +++ b/pw_trace_tokenized/py/BUILD.gn @@ -17,10 +17,12 @@ import("//build_overrides/pigweed.gni") import("$dir_pw_build/python.gni") pw_python_package("py") { - setup = [ - "pyproject.toml", - "setup.cfg", - ] + generate_setup = { + metadata = { + name = "pw_trace_tokenized" + version = "0.0.1" + } + } sources = [ "pw_trace_tokenized/__init__.py", "pw_trace_tokenized/get_trace.py", @@ -34,4 +36,5 @@ pw_python_package("py") { ] pylintrc = "$dir_pigweed/.pylintrc" mypy_ini = "$dir_pigweed/.mypy.ini" + proto_library = "..:protos" } diff --git a/pw_trace_tokenized/py/pyproject.toml b/pw_trace_tokenized/py/pyproject.toml deleted file mode 100644 index 798b747ec..000000000 --- a/pw_trace_tokenized/py/pyproject.toml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2021 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -[build-system] -requires = ['setuptools', 'wheel'] -build-backend = 'setuptools.build_meta' diff --git a/pw_trace_tokenized/py/setup.cfg b/pw_trace_tokenized/py/setup.cfg deleted file mode 100644 index 98038d397..000000000 --- a/pw_trace_tokenized/py/setup.cfg +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2021 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -[metadata] -name = pw_trace_tokenized -version = 0.0.1 -author = Pigweed Authors -author_email = pigweed-developers@googlegroups.com -description = pw_trace backend to tokenize trace events - -[options] -packages = find: -zip_safe = False -install_requires = - pyserial>=3.5,<4.0 - types-pyserial>=3.5,<4.0 - -[options.package_data] -pw_trace_tokenized = py.typed diff --git a/pw_trace_tokenized/trace_service_pwpb.cc b/pw_trace_tokenized/trace_service_pwpb.cc new file mode 100644 index 000000000..af4b90a7c --- /dev/null +++ b/pw_trace_tokenized/trace_service_pwpb.cc @@ -0,0 +1,75 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pw_trace_tokenized/trace_service_pwpb.h" + +#include "pw_chrono/system_clock.h" + +namespace pw::trace { + +TraceService::TraceService(TokenizedTracer& tokenized_tracer, + stream::Writer& trace_writer) + : BaseTraceService(tokenized_tracer, trace_writer) {} + +Status TraceService::Start( + const proto::pwpb::StartRequest::Message& /*request*/, + proto::pwpb::StartResponse::Message& /*response*/) { + return BaseTraceService::Start(); +} + +Status TraceService::Stop(const proto::pwpb::StopRequest::Message& /*request*/, + proto::pwpb::StopResponse::Message& response) { + if (auto status = BaseTraceService::Stop(); status != pw::OkStatus()) { + return status; + } + + response.file_id = transfer_id_; + return pw::OkStatus(); +} + +Status TraceService::GetClockParameters( + const proto::pwpb::ClockParametersRequest::Message& /*request*/, + proto::pwpb::ClockParametersResponse::Message& response) { + response.clock_parameters.tick_period_seconds_numerator = + PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR; + response.clock_parameters.tick_period_seconds_denominator = + PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR; + + switch (chrono::SystemClock::epoch) { + case chrono::Epoch::kUnknown: + response.clock_parameters.epoch_type = + chrono::pwpb::EpochType::Enum::kUnknown; + break; + case chrono::Epoch::kTimeSinceBoot: + response.clock_parameters.epoch_type = + chrono::pwpb::EpochType::Enum::kTimeSinceBoot; + break; + case chrono::Epoch::kUtcWallClock: + response.clock_parameters.epoch_type = + chrono::pwpb::EpochType::Enum::kUtcWallClock; + break; + case chrono::Epoch::kGpsWallClock: + response.clock_parameters.epoch_type = + chrono::pwpb::EpochType::Enum::kGpsWallClock; + break; + case chrono::Epoch::kTaiWallClock: + response.clock_parameters.epoch_type = + chrono::pwpb::EpochType::Enum::kTaiWallClock; + break; + } + + return pw::OkStatus(); +} + +} // namespace pw::trace diff --git a/pw_trace_tokenized/trace_service_pwpb_test.cc b/pw_trace_tokenized/trace_service_pwpb_test.cc new file mode 100644 index 000000000..008210193 --- /dev/null +++ b/pw_trace_tokenized/trace_service_pwpb_test.cc @@ -0,0 +1,130 @@ +// Copyright 2023 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pw_trace_tokenized/trace_service_pwpb.h" + +#include "gtest/gtest.h" +#include "pw_chrono/system_clock.h" +#include "pw_rpc/pwpb/test_method_context.h" +#include "pw_stream/memory_stream.h" +#include "pw_trace/trace.h" +#include "pw_trace_tokenized/trace_tokenized.h" + +namespace pw::trace { + +class TraceServiceTest : public ::testing::Test { + public: + TraceServiceTest() {} + + static constexpr uint32_t kTraceTransferHandlerId = 7; +}; + +TEST_F(TraceServiceTest, Start) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Start) + context(tracer, writer); + + ASSERT_FALSE(tracer.IsEnabled()); + ASSERT_EQ(context.call({}), OkStatus()); + ASSERT_TRUE(tracer.IsEnabled()); + + // multiple calls to start are disallowed + ASSERT_EQ(context.call({}), Status::FailedPrecondition()); +} + +TEST_F(TraceServiceTest, Stop) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop) + context(tracer, writer); + context.service().SetTransferId(kTraceTransferHandlerId); + + tracer.Enable(true); + PW_TRACE_INSTANT("TestTrace"); + + ASSERT_EQ(context.call({}), OkStatus()); + ASSERT_FALSE(tracer.IsEnabled()); + EXPECT_EQ(kTraceTransferHandlerId, context.response().file_id); + EXPECT_LT(0u, writer.bytes_written()); +} + +TEST_F(TraceServiceTest, StopNoTransferHandlerId) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop) + context(tracer, writer); + + tracer.Enable(true); + PW_TRACE_INSTANT("TestTrace"); + + ASSERT_EQ(context.call({}), OkStatus()); + ASSERT_FALSE(tracer.IsEnabled()); + EXPECT_FALSE(context.response().file_id.has_value()); + EXPECT_LT(0u, writer.bytes_written()); +} + +TEST_F(TraceServiceTest, StopNotStarted) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop) + context(tracer, writer); + + // stopping while tracing is disabled results in FailedPrecondition + ASSERT_EQ(context.call({}), Status::FailedPrecondition()); +} + +TEST_F(TraceServiceTest, StopNoData) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, Stop) + context(tracer, writer); + + tracer.Enable(true); + + // stopping with no trace data results in Unavailable + ASSERT_EQ(context.call({}), Status::Unavailable()); +} + +TEST_F(TraceServiceTest, GetClockParameters) { + auto& tracer = trace::GetTokenizedTracer(); + + std::array<std::byte, PW_TRACE_BUFFER_SIZE_BYTES> dest_buffer; + stream::MemoryWriter writer(dest_buffer); + + PW_PWPB_TEST_METHOD_CONTEXT(TraceService, GetClockParameters) + context(tracer, writer); + + ASSERT_EQ(context.call({}), OkStatus()); + EXPECT_EQ(PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR, + context.response().clock_parameters.tick_period_seconds_numerator); + EXPECT_EQ( + PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR, + context.response().clock_parameters.tick_period_seconds_denominator); + EXPECT_EQ( + static_cast<int32_t>(chrono::SystemClock::epoch), + static_cast<int32_t>(*context.response().clock_parameters.epoch_type)); +} + +} // namespace pw::trace |