blob: d82ecbb8bb21334b39aa6f616e571d5f1cb3ab01 [file] [log] [blame]
Florian Mayer75905df2018-05-08 17:44:08 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Print timestamps when pages were read to stdout.
18// This data is useful to compute rate of events from the kernel.
19
20#include <thread>
21
22#include <fcntl.h> // splice
23#include <inttypes.h>
24#include <stdint.h>
25#include <unistd.h> // pipe
26
27#include "perfetto/base/logging.h"
28#include "perfetto/base/scoped_file.h"
29#include "perfetto/base/time.h"
30#include "perfetto/base/utils.h"
31
32namespace perfetto {
33namespace {
34
35void SetBlocking(int fd, bool is_blocking) {
36 int flags = fcntl(fd, F_GETFL, 0);
37 flags = (is_blocking) ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
38 PERFETTO_CHECK(fcntl(fd, F_SETFL, flags) == 0);
39}
40
41__attribute__((__noreturn__)) void ReadLoop(int fd) {
42 char buf[4096];
43 while (true) {
44 base::ignore_result(read(fd, &buf, sizeof(buf)));
45 }
46}
47
48int PipestatsMain(int argc, char** argv) {
49 PERFETTO_CHECK(argc == 2);
50 base::ScopedFile trace_fd(open(argv[1], O_RDONLY));
51 PERFETTO_CHECK(trace_fd);
52 std::thread reader(ReadLoop, trace_fd.get());
53
54 int pipe_fds[2];
55 PERFETTO_CHECK(pipe(&pipe_fds[0]) == 0);
56 base::ScopedFile staging_read_fd(pipe_fds[0]);
57 base::ScopedFile staging_write_fd(pipe_fds[1]);
58
59 // Make reads from the raw pipe blocking so that splice() can sleep.
60 SetBlocking(*trace_fd, true);
61
62 // Reads from the staging pipe are always non-blocking.
63 SetBlocking(*staging_read_fd, false);
64
65 // Note: O_NONBLOCK seems to be ignored by splice() on the target pipe. The
66 // blocking vs non-blocking behavior is controlled solely by the
67 // SPLICE_F_NONBLOCK flag passed to splice().
68 SetBlocking(*staging_write_fd, false);
69
70 while (true) {
71 ssize_t splice_res = splice(*trace_fd, nullptr, *staging_write_fd, nullptr,
72 base::kPageSize, SPLICE_F_MOVE);
73 if (splice_res > 0) {
74 auto cur = base::GetWallTimeNs();
75 printf("%" PRId64 "\n", int64_t(cur.count()));
76 }
77 }
78}
79
80} // namespace
81} // namespace perfetto
82
83int main(int argc, char** argv) {
84 return perfetto::PipestatsMain(argc, argv);
85}