Skip to content

Commit 8b1cd2d

Browse files
happyCoder92copybara-github
authored andcommitted
Add a simple setup latency profiling
PiperOrigin-RevId: 941651211 Change-Id: Id63fabbebea6b8a1e78387ce371ea3a1b3f79d5a
1 parent 7f9a1ae commit 8b1cd2d

14 files changed

Lines changed: 417 additions & 8 deletions

sandboxed_api/sandbox2/BUILD

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -659,21 +659,20 @@ cc_library(
659659
":comms",
660660
":fork_client",
661661
":forkserver_cc_proto",
662+
":latency_stop_watch",
662663
":mounts",
663664
":namespace",
664665
":policy",
665666
":sanitizer",
667+
":setup_latency_breakdown",
666668
":syscall",
667669
":util",
668-
":version",
669670
"//sandboxed_api/sandbox2/util:bpf_helper",
670671
"//sandboxed_api/util:fileops",
671672
"//sandboxed_api/util:raw_logging",
672673
"@abseil-cpp//absl/base:core_headers",
673674
"@abseil-cpp//absl/container:flat_hash_map",
674-
"@abseil-cpp//absl/container:flat_hash_set",
675675
"@abseil-cpp//absl/status",
676-
"@abseil-cpp//absl/status:statusor",
677676
"@abseil-cpp//absl/strings",
678677
"@libcap",
679678
],
@@ -689,7 +688,9 @@ cc_library(
689688
":fork_client",
690689
":forkedprocess",
691690
":forkserver_cc_proto",
691+
":latency_stop_watch",
692692
":namespace",
693+
":setup_latency_breakdown",
693694
":util",
694695
"//sandboxed_api/util:fileops",
695696
"//sandboxed_api/util:raw_logging",
@@ -711,10 +712,12 @@ cc_library(
711712
visibility = ["//visibility:public"],
712713
deps = [
713714
":comms",
715+
":flags",
714716
":forkserver_cc_proto",
715-
":version",
717+
":setup_latency_breakdown",
716718
"//sandboxed_api/util:fileops",
717719
"@abseil-cpp//absl/base:core_headers",
720+
"@abseil-cpp//absl/flags:flag",
718721
"@abseil-cpp//absl/log",
719722
"@abseil-cpp//absl/log:check",
720723
"@abseil-cpp//absl/status",
@@ -1309,3 +1312,36 @@ cc_library(
13091312
"@abseil-cpp//absl/strings",
13101313
],
13111314
)
1315+
1316+
cc_library(
1317+
name = "setup_latency_breakdown",
1318+
srcs = ["setup_latency_breakdown.cc"],
1319+
hdrs = ["setup_latency_breakdown.h"],
1320+
copts = sapi_platform_copts(),
1321+
deps = [
1322+
":comms",
1323+
"//sandboxed_api/util:raw_logging",
1324+
"@abseil-cpp//absl/time",
1325+
],
1326+
)
1327+
1328+
cc_library(
1329+
name = "latency_stop_watch",
1330+
srcs = ["latency_stop_watch.cc"],
1331+
hdrs = ["latency_stop_watch.h"],
1332+
copts = sapi_platform_copts(),
1333+
deps = [
1334+
"@abseil-cpp//absl/time",
1335+
],
1336+
)
1337+
1338+
cc_test(
1339+
name = "latency_stop_watch_test",
1340+
srcs = ["latency_stop_watch_test.cc"],
1341+
copts = sapi_platform_copts(),
1342+
deps = [
1343+
":latency_stop_watch",
1344+
"@abseil-cpp//absl/time",
1345+
"@googletest//:gtest_main",
1346+
],
1347+
)

sandboxed_api/sandbox2/CMakeLists.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,12 @@ target_link_libraries(sandbox2_forkedprocess
637637
sandbox2::bpf_helper
638638
sandbox2::client
639639
sandbox2::fork_client
640+
sandbox2::latency_stop_watch
640641
sandbox2::mounts
641642
sandbox2::namespace
642643
sandbox2::policy
643644
sandbox2::sanitizer
645+
sandbox2::setup_latency_breakdown
644646
sandbox2::syscall
645647
sandbox2::util
646648
sapi::base
@@ -666,7 +668,9 @@ target_link_libraries(sandbox2_forkserver
666668
sandbox2::fork_client
667669
sandbox2::forkedprocess
668670
sandbox2::forkserver_proto
671+
sandbox2::latency_stop_watch
669672
sandbox2::namespace
673+
sandbox2::setup_latency_breakdown
670674
sandbox2::util
671675
sapi::base
672676
sandbox2::version
@@ -683,7 +687,9 @@ add_library(sandbox2_fork_client ${SAPI_LIB_TYPE}
683687
add_library(sandbox2::fork_client ALIAS sandbox2_fork_client)
684688
target_link_libraries(sandbox2_fork_client
685689
PRIVATE absl::status
690+
sandbox2::flags
686691
sandbox2::forkserver_proto
692+
sandbox2::setup_latency_breakdown
687693
sandbox2::version
688694
PUBLIC absl::core_headers
689695
absl::statusor
@@ -914,6 +920,29 @@ target_link_libraries(sandbox2_version
914920
PUBLIC absl::strings
915921
PRIVATE sapi::base)
916922

923+
# sandboxed_api/sandbox2:setup_latency_breakdown
924+
add_library(sandbox2_setup_latency_breakdown STATIC
925+
setup_latency_breakdown.cc
926+
setup_latency_breakdown.h
927+
)
928+
add_library(sandbox2::setup_latency_breakdown ALIAS sandbox2_setup_latency_breakdown)
929+
target_link_libraries(sandbox2_setup_latency_breakdown
930+
PRIVATE sapi::base
931+
PUBLIC sandbox2::comms
932+
sapi::raw_logging
933+
absl::time
934+
)
935+
936+
# sandboxed_api/sandbox2:latency_stop_watch
937+
add_library(sandbox2_latency_stop_watch STATIC
938+
latency_stop_watch.cc
939+
latency_stop_watch.h
940+
)
941+
add_library(sandbox2::latency_stop_watch ALIAS sandbox2_latency_stop_watch)
942+
target_link_libraries(sandbox2_latency_stop_watch
943+
PRIVATE sapi::base
944+
PUBLIC absl::time
945+
)
917946

918947
if(BUILD_TESTING AND SAPI_BUILD_TESTING)
919948
add_subdirectory(testcases)
@@ -1402,6 +1431,22 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING)
14021431
ENVIRONMENT "TEST_SRCDIR=${PROJECT_BINARY_DIR}"
14031432
)
14041433

1434+
# sandboxed_api/sandbox2:latency_stop_watch_test
1435+
add_executable(sandbox2_latency_stop_watch_test
1436+
latency_stop_watch_test.cc
1437+
)
1438+
set_target_properties(sandbox2_latency_stop_watch_test PROPERTIES
1439+
OUTPUT_NAME latency_stop_watch_test
1440+
)
1441+
target_link_libraries(sandbox2_latency_stop_watch_test
1442+
PRIVATE sandbox2::latency_stop_watch
1443+
sapi::test_main
1444+
)
1445+
gtest_discover_tests_xcompile(sandbox2_latency_stop_watch_test PROPERTIES
1446+
ENVIRONMENT "TEST_TMPDIR=/tmp"
1447+
ENVIRONMENT "TEST_SRCDIR=${PROJECT_BINARY_DIR}"
1448+
)
1449+
14051450
endif()
14061451

14071452
configure_file(

sandboxed_api/sandbox2/comms.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class Comms {
7676
static constexpr uint32_t kTagCreds = 0X80000202;
7777
static constexpr uint32_t kTagCommsUpgrade = 0x80000203;
7878
static constexpr uint32_t kTagCommsNoUpgrade = 0x80000204;
79+
static constexpr uint32_t kTagLatencyBreakdown = 0x80000205;
7980

8081
// Any payload size above this limit will LOG(WARNING).
8182
static constexpr size_t kWarnMsgSize = (256ULL << 20);

sandboxed_api/sandbox2/flags.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ ABSL_FLAG(int, sandbox2_deadline_manager_signal, SIGRTMAX - 1,
6767
"Signal to use for deadline notifications - must be not otherwise "
6868
"used by the process (default: SIGRTMAX - 1)");
6969

70+
// sandbox2:fork_client
71+
ABSL_FLAG(bool, sandbox2_log_setup_latency_breakdown, false,
72+
"If set, sandbox2 will log the setup latency breakdown for each "
73+
"started sandboxee");
74+
7075
namespace sandbox2 {
7176

7277
bool AbslParseFlag(absl::string_view text, GlobalForkserverStartModeSet* out,

sandboxed_api/sandbox2/flags.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@ ABSL_DECLARE_FLAG(bool, sandbox_libunwind_crash_handler); // retired flag
8989
// sandbox2/util:deadline_manager
9090
ABSL_DECLARE_FLAG(int, sandbox2_deadline_manager_signal);
9191

92+
// sandbox2:fork_client
93+
ABSL_DECLARE_FLAG(bool, sandbox2_log_setup_latency_breakdown);
94+
9295
#endif // SANDBOXED_API_SANDBOX2_FLAGS_H_

sandboxed_api/sandbox2/fork_client.cc

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,41 @@
1616

1717
#include <sys/types.h>
1818

19+
#include <string>
1920
#include <utility>
2021

22+
#include "absl/flags/flag.h"
2123
#include "absl/log/check.h"
2224
#include "absl/log/log.h"
2325
#include "absl/status/status.h"
2426
#include "absl/strings/str_cat.h"
2527
#include "absl/synchronization/mutex.h"
2628
#include "sandboxed_api/sandbox2/comms.h"
29+
#include "sandboxed_api/sandbox2/flags.h"
2730
#include "sandboxed_api/sandbox2/forkserver.pb.h"
31+
#include "sandboxed_api/sandbox2/setup_latency_breakdown.h"
2832
#include "sandboxed_api/util/fileops.h"
2933

3034
namespace sandbox2 {
31-
35+
namespace {
3236
using ::sapi::file_util::fileops::FDCloser;
3337

38+
void ReportLatency(const SetupLatencyBreakdown& latency_breakdown) {
39+
if (!absl::GetFlag(FLAGS_sandbox2_log_setup_latency_breakdown)) {
40+
return;
41+
}
42+
LOG(INFO) << "Setup latency breakdown:";
43+
for (int i = 0; i < SetupLatencyBreakdown::kNumSetupSteps; ++i) {
44+
LOG(INFO) << " "
45+
<< SetupLatencyBreakdown::SetupStepToString(
46+
static_cast<SetupLatencyBreakdown::SetupStep>(i))
47+
<< ": "
48+
<< latency_breakdown.GetLatency(
49+
static_cast<SetupLatencyBreakdown::SetupStep>(i));
50+
}
51+
}
52+
} // namespace
53+
3454
ForkClient::ForkClient(pid_t pid, Comms* comms, bool is_global)
3555
: pid_(pid), comms_(comms), is_global_(is_global) {
3656
}
@@ -117,6 +137,15 @@ absl::StatusOr<SandboxeeProcess> ForkClient::PendingRequest::Finalize(
117137
return absl::InternalError(
118138
"Receiving sandboxee PID from the ForkServer failed");
119139
}
140+
141+
// Receive setup latency tracer data and report it.
142+
if (SetupLatencyBreakdown latency_breakdown;
143+
latency_breakdown.Receive(setup_comms_)) {
144+
ReportLatency(latency_breakdown);
145+
} else {
146+
LOG(WARNING) << "Failed to receive setup latency tracer data";
147+
}
148+
120149
return process;
121150
}
122151

sandboxed_api/sandbox2/forkedprocess.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@
4444
#include "sandboxed_api/sandbox2/comms.h"
4545
#include "sandboxed_api/sandbox2/fork_client.h"
4646
#include "sandboxed_api/sandbox2/forkserver.pb.h"
47+
#include "sandboxed_api/sandbox2/latency_stop_watch.h"
4748
#include "sandboxed_api/sandbox2/mounts.h"
4849
#include "sandboxed_api/sandbox2/namespace.h"
4950
#include "sandboxed_api/sandbox2/policy.h"
5051
#include "sandboxed_api/sandbox2/sanitizer.h"
52+
#include "sandboxed_api/sandbox2/setup_latency_breakdown.h"
5153
#include "sandboxed_api/sandbox2/syscall.h"
5254
#include "sandboxed_api/sandbox2/util.h"
5355
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
@@ -379,6 +381,8 @@ void ForkedProcess::SetupNamespaces(FDCloser initial_userns_fd,
379381
// We'll continue just in the child.
380382
_exit(0);
381383
}
384+
latency_breakdown_.SetLatency(SetupLatencyBreakdown::kInitFork,
385+
latency_stop_watch_.LapTime());
382386
}
383387
SanitizeEnvironment();
384388
JoinNamespaces(std::move(initial_mntns_fd), std::move(shared_netns_fd));
@@ -388,13 +392,23 @@ void ForkedProcess::SetupNamespaces(FDCloser initial_userns_fd,
388392
if (request_.netns_mode() == NETNS_MODE_SHARED_PER_FORKSERVER) {
389393
unshare_flags &= ~CLONE_NEWNET;
390394
}
395+
396+
latency_breakdown_.SetLatency(SetupLatencyBreakdown::kTillNamespacesUnshare,
397+
latency_stop_watch_.LapTime());
391398
SAPI_RAW_PCHECK(unshare(unshare_flags) == 0, "unsharing namespaces");
399+
latency_breakdown_.SetLatency(SetupLatencyBreakdown::kNamespacesUnshare,
400+
latency_stop_watch_.LapTime());
392401
Namespace::InitializeNamespaces(
393402
uid, gid, request_.clone_flags(), Mounts(request_.mount_tree()),
394403
request_.hostname(), request_.allow_mount_propagation(),
395404
request_.allow_write_executable());
405+
latency_breakdown_.SetLatency(
406+
SetupLatencyBreakdown::kNamespacesInitialization,
407+
latency_stop_watch_.LapTime());
396408
if (has_newpid) {
397409
LaunchInit();
410+
latency_breakdown_.SetLatency(SetupLatencyBreakdown::kInitLaunch,
411+
latency_stop_watch_.LapTime());
398412
}
399413
}
400414

@@ -434,6 +448,9 @@ Comms ForkedProcess::Setup(FDCloser initial_userns_fd,
434448
DropAllCapabilities();
435449
// Send sandboxee pid.
436450
SAPI_RAW_CHECK(setup_comms_.SendCreds(), "Failed to send sandboxee_pid");
451+
latency_breakdown_.SetLatency(SetupLatencyBreakdown::kTillAlmostDone,
452+
latency_stop_watch_.LapTime());
453+
latency_breakdown_.Send(setup_comms_);
437454
setup_comms_.Terminate();
438455
if (will_exec) {
439456
LaunchSandboxee();

sandboxed_api/sandbox2/forkedprocess.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@
2121

2222
#include "sandboxed_api/sandbox2/comms.h"
2323
#include "sandboxed_api/sandbox2/forkserver.pb.h"
24+
#include "sandboxed_api/sandbox2/latency_stop_watch.h"
25+
#include "sandboxed_api/sandbox2/setup_latency_breakdown.h"
2426
#include "sandboxed_api/util/fileops.h"
2527

2628
namespace sandbox2 {
2729

2830
class ForkedProcess {
2931
public:
30-
ForkedProcess(ForkRequest request, Comms setup_comms)
31-
: request_(std::move(request)), setup_comms_(std::move(setup_comms)) {}
32+
ForkedProcess(ForkRequest request, Comms setup_comms,
33+
SetupLatencyBreakdown latency_breakdown)
34+
: request_(std::move(request)),
35+
setup_comms_(std::move(setup_comms)),
36+
latency_breakdown_(std::move(latency_breakdown)) {}
3237
// Returns the comms channel for the newly setup sandboxee.
3338
Comms Setup(sapi::file_util::fileops::FDCloser initial_userns_fd,
3439
sapi::file_util::fileops::FDCloser initial_mntns_fd,
@@ -52,6 +57,8 @@ class ForkedProcess {
5257

5358
ForkRequest request_;
5459
Comms setup_comms_;
60+
SetupLatencyBreakdown latency_breakdown_;
61+
LatencyStopWatch latency_stop_watch_;
5562
std::vector<std::string> args_;
5663
std::vector<std::string> envp_;
5764
sapi::file_util::fileops::FDCloser comms_fd_;

sandboxed_api/sandbox2/forkserver.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@
4747
#include "sandboxed_api/sandbox2/fork_client.h"
4848
#include "sandboxed_api/sandbox2/forkedprocess.h"
4949
#include "sandboxed_api/sandbox2/forkserver.pb.h"
50+
#include "sandboxed_api/sandbox2/latency_stop_watch.h"
5051
#include "sandboxed_api/sandbox2/namespace.h"
52+
#include "sandboxed_api/sandbox2/setup_latency_breakdown.h"
5153
#include "sandboxed_api/sandbox2/util.h"
5254
#include "sandboxed_api/util/fileops.h"
5355
#include "sandboxed_api/util/raw_logging.h"
@@ -117,6 +119,8 @@ pid_t ForkServer::ServeRequest() {
117119
}
118120
SAPI_RAW_LOG(FATAL, "Failed to receive ForkServer request");
119121
}
122+
SetupLatencyBreakdown latency_breakdown;
123+
LatencyStopWatch latency_stop_watch;
120124
SAPI_RAW_CHECK(fork_request.mode() != FORKSERVER_FORK_UNSPECIFIED,
121125
"Forkserver mode is unspecified");
122126
if (fork_request.clone_flags() & CLONE_NEWNS) {
@@ -125,6 +129,8 @@ pid_t ForkServer::ServeRequest() {
125129
if (fork_request.netns_mode() == NETNS_MODE_SHARED_PER_FORKSERVER) {
126130
CreateForkserverSharedNetworkNamespace();
127131
}
132+
latency_breakdown.SetLatency(SetupLatencyBreakdown::kSharedNamespacesCreation,
133+
latency_stop_watch.LapTime());
128134

129135
// Create a new comms channel to coordinate the child setup.
130136
Comms setup_comms = [this] {
@@ -133,6 +139,8 @@ pid_t ForkServer::ServeRequest() {
133139
"Failed to send setup socket");
134140
return Comms(setup_socketpair.sock[0].Release());
135141
}();
142+
latency_breakdown.SetLatency(SetupLatencyBreakdown::kSetupCommsCreation,
143+
latency_stop_watch.LapTime());
136144

137145
// We fork a child early on to do the rest of the setup.
138146
const bool has_namespaces = fork_request.clone_flags() & CLONE_NEWUSER;
@@ -148,9 +156,12 @@ pid_t ForkServer::ServeRequest() {
148156
}
149157
SAPI_RAW_PCHECK(pid != -1, "fork failed");
150158
if (pid == 0) {
159+
latency_breakdown.SetLatency(SetupLatencyBreakdown::kSetupProcessFork,
160+
latency_stop_watch.LapTime());
151161
// Make sure we don't use the forkserver's comms in the forked process.
152162
comms_->Terminate();
153-
ForkedProcess forked(fork_request, std::move(setup_comms));
163+
ForkedProcess forked(fork_request, std::move(setup_comms),
164+
latency_breakdown);
154165
*comms_ =
155166
forked.Setup(std::move(initial_userns_fd_),
156167
std::move(initial_mntns_fd_), std::move(shared_netns_fd_));

0 commit comments

Comments
 (0)