summaryrefslogtreecommitdiffstats
path: root/include/utils/Trace.h
blob: f33ddf652d40fcc19e7d5721db6273da9b792518 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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
 *
 *      http://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.
 */

#ifndef ANDROID_TRACE_H
#define ANDROID_TRACE_H

#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <cutils/compiler.h>
#include <utils/threads.h>

// The ATRACE_TAG macro can be defined before including this header to trace
// using one of the tags defined below.  It must be defined to one of the
// following ATRACE_TAG_* macros.  The trace tag is used to filter tracing in
// userland to avoid some of the runtime cost of tracing when it is not desired.
//
// Defining ATRACE_TAG to be ATRACE_TAG_ALWAYS will result in the tracing always
// being enabled - this should ONLY be done for debug code, as userland tracing
// has a performance cost even when the trace is not being recorded.  Defining
// ATRACE_TAG to be ATRACE_TAG_NEVER or leaving ATRACE_TAG undefined will result
// in the tracing always being disabled.
#define ATRACE_TAG_NEVER    0           // The "never" tag is never enabled.
#define ATRACE_TAG_ALWAYS   (1<<0)      // The "always" tag is always enabled.
#define ATRACE_TAG_GRAPHICS (1<<1)
#define ATRACE_TAG_LAST     (1<<1)

#define ATRACE_TAG_INVALID (~((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST))

#ifndef ATRACE_TAG
#define ATRACE_TAG ATRACE_TAG_NEVER
#elif ATRACE_TAG > ATRACE_TAG_LAST
#error ATRACE_TAG must be defined to be one of the tags defined in utils/Trace.h
#endif

// ATRACE_CALL traces the beginning and end of the current function.  To trace
// the correct start and end times this macro should be the first line of the
// function body.
#define ATRACE_CALL() android::ScopedTrace ___tracer(ATRACE_TAG, __FUNCTION__)

// ATRACE_INT traces a named integer value.  This can be used to track how the
// value changes over time in a trace.
#define ATRACE_INT(name, value) android::Tracer::traceCounter(ATRACE_TAG, name, value)

namespace android {

class Tracer {

public:

    static inline void traceCounter(uint64_t tag, const char* name,
            int32_t value) {
        if (!android_atomic_acquire_load(&sIsReady)) {
            init();
        }
        int traceFD = sTraceFD;
        if (CC_UNLIKELY(tagEnabled(tag) && traceFD != -1)) {
            char buf[1024];
            snprintf(buf, 1024, "C|%d|%s|%d", getpid(), name, value);
            write(traceFD, buf, strlen(buf));
        }
    }

    static inline void traceBegin(uint64_t tag, const char* name) {
        if (CC_UNLIKELY(!android_atomic_acquire_load(&sIsReady))) {
            init();
        }
        int traceFD = sTraceFD;
        if (CC_UNLIKELY(tagEnabled(tag) && (traceFD != -1))) {
            char buf[1024];
            size_t len = snprintf(buf, 1024, "B|%d|%s", getpid(), name);
            write(traceFD, buf, len);
        }
    }

   static inline void traceEnd(uint64_t tag) {
        if (CC_UNLIKELY(!android_atomic_acquire_load(&sIsReady))) {
            init();
        }
        int traceFD = sTraceFD;
        if (CC_UNLIKELY(tagEnabled(tag) && (traceFD != -1))) {
            char buf = 'E';
            write(traceFD, &buf, 1);
        }
    }

private:

    static inline bool tagEnabled(uint64_t tag) {
        return !(tag & ATRACE_TAG_INVALID) && (tag & sEnabledTags);
    }

    // init opens the trace marker file for writing and reads the
    // atrace.tags.enableflags system property.  It does this only the first
    // time it is run, using sMutex for synchronization.
    static void init();

    // sIsReady is a boolean value indicating whether a call to init() has
    // completed in this process.  It is initialized to 0 and set to 1 when the
    // first init() call completes.  It is set to 1 even if a failure occurred
    // in init (e.g. the trace marker file couldn't be opened).
    //
    // This should be checked by all tracing functions using an atomic acquire
    // load operation before calling init().  This check avoids the need to lock
    // a mutex each time a trace function gets called.
    static volatile int32_t sIsReady;

    // sTraceFD is the file descriptor used to write to the kernel's trace
    // buffer.  It is initialized to -1 and set to an open file descriptor in
    // init() while a lock on sMutex is held.
    //
    // This should only be used by a trace function after init() has
    // successfully completed.
    static int sTraceFD;

    // sEnabledTags is the set of tag bits for which tracing is currently
    // enabled.  It is initialized to 0 and set based on the
    // atrace.tags.enableflags system property in init() while a lock on sMutex
    // is held.
    //
    // This should only be used by a trace function after init() has
    // successfully completed.
    static uint64_t sEnabledTags;

    // sMutex is used to protect the execution of init().
    static Mutex sMutex;
};

class ScopedTrace {

public:
    inline ScopedTrace(uint64_t tag, const char* name) :
            mTag(tag) {
        Tracer::traceBegin(mTag, name);
    }

    inline ~ScopedTrace() {
        Tracer::traceEnd(mTag);
    }

private:

    uint64_t mTag;
};

}; // namespace android

#endif // ANDROID_TRACE_H