1#ifndef MEMPROF_DATA_INC
2#define MEMPROF_DATA_INC
3/*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\
4|*
5|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6|* See https://llvm.org/LICENSE.txt for license information.
7|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8|*
9\*===----------------------------------------------------------------------===*/
10/*
11 * This is the main file that defines all the data structure, signature,
12 * constant literals that are shared across profiling runtime library,
13 * and host tools (reader/writer).
14 *
15 * This file has two identical copies. The primary copy lives in LLVM and
16 * the other one sits in compiler-rt/include/profile directory. To make changes
17 * in this file, first modify the primary copy and copy it over to compiler-rt.
18 * Testing of any change in this file can start only after the two copies are
19 * synced up.
20 *
21\*===----------------------------------------------------------------------===*/
22
23#ifdef _MSC_VER
24#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
25#else
26#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
27#endif
28
29// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
30#define MEMPROF_RAW_MAGIC_64                                                                        \
31  ((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 |          \
32   (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
33
34// The version number of the raw binary format.
35#define MEMPROF_RAW_VERSION 1ULL
36
37namespace llvm {
38namespace memprof {
39// A struct describing the header used for the raw binary memprof profile format.
40PACKED(struct Header {
41  uint64_t Magic;
42  uint64_t Version;
43  uint64_t TotalSize;
44  uint64_t SegmentOffset;
45  uint64_t MIBOffset;
46  uint64_t StackOffset;
47});
48
49
50// A struct describing the information necessary to describe a /proc/maps
51// segment entry for a particular binary/library identified by its build id.
52PACKED(struct SegmentEntry {
53  uint64_t Start;
54  uint64_t End;
55  uint64_t Offset;
56  // This field is unused until sanitizer procmaps support for build ids for
57  // Linux-Elf is implemented.
58  uint8_t BuildId[32] = {0};
59
60  SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
61    Start(S), End(E), Offset(O) {}
62
63  SegmentEntry(const SegmentEntry& S) {
64    Start = S.Start;
65    End = S.End;
66    Offset = S.Offset;
67  }
68
69  SegmentEntry& operator=(const SegmentEntry& S) {
70    Start = S.Start;
71    End = S.End;
72    Offset = S.Offset;
73    return *this;
74  }
75
76  bool operator==(const SegmentEntry& S) const {
77    return Start == S.Start &&
78           End == S.End &&
79           Offset == S.Offset;
80  }
81});
82
83// A struct representing the heap allocation characteristics of a particular
84// runtime context. This struct is shared between the compiler-rt runtime and
85// the raw profile reader. The indexed format uses a separate, self-describing
86// backwards compatible format.
87PACKED(struct MemInfoBlock {
88  uint32_t alloc_count;
89  uint64_t total_access_count, min_access_count, max_access_count;
90  uint64_t total_size;
91  uint32_t min_size, max_size;
92  uint32_t alloc_timestamp, dealloc_timestamp;
93  uint64_t total_lifetime;
94  uint32_t min_lifetime, max_lifetime;
95  uint32_t alloc_cpu_id, dealloc_cpu_id;
96  uint32_t num_migrated_cpu;
97
98  // Only compared to prior deallocated object currently.
99  uint32_t num_lifetime_overlaps;
100  uint32_t num_same_alloc_cpu;
101  uint32_t num_same_dealloc_cpu;
102
103  uint64_t data_type_id; // TODO: hash of type name
104
105  MemInfoBlock() : alloc_count(0) {}
106
107  MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
108               uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
109      : alloc_count(1), total_access_count(access_count),
110        min_access_count(access_count), max_access_count(access_count),
111        total_size(size), min_size(size), max_size(size),
112        alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp),
113        total_lifetime(dealloc_timestamp - alloc_timestamp),
114        min_lifetime(total_lifetime), max_lifetime(total_lifetime),
115        alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu),
116        num_lifetime_overlaps(0), num_same_alloc_cpu(0),
117        num_same_dealloc_cpu(0) {
118    num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id;
119  }
120
121  void Merge(const MemInfoBlock &newMIB) {
122    alloc_count += newMIB.alloc_count;
123
124    total_access_count += newMIB.total_access_count;
125    min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count;
126    max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count;
127
128    total_size += newMIB.total_size;
129    min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size;
130    max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size;
131
132    total_lifetime += newMIB.total_lifetime;
133    min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime;
134    max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime;
135
136    // We know newMIB was deallocated later, so just need to check if it was
137    // allocated before last one deallocated.
138    num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp;
139    alloc_timestamp = newMIB.alloc_timestamp;
140    dealloc_timestamp = newMIB.dealloc_timestamp;
141
142    num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id;
143    num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id;
144    alloc_cpu_id = newMIB.alloc_cpu_id;
145    dealloc_cpu_id = newMIB.dealloc_cpu_id;
146  }
147});
148
149} // namespace memprof
150} // namespace llvm
151
152#endif
153