]>
git.saurik.com Git - apple/system_cmds.git/blob - kdprof/SaveTraceAction.cpp
ce95b375a98d5b1a8e135c73007bde4912efddd8
5 // Created by James McIlree on 5/2/13.
6 // Copyright (c) 2013 Apple. All rights reserved.
11 template <typename SIZE
>
12 static void execute_arch_specific(Globals
& globals
, KDState
& state
, FileDescriptor
& save_fd
) {
13 // Collect all data first, printing takes time...
14 auto threadmap
= KDBG::threadmap
<SIZE
>(state
);
15 auto cpumap
= KDBG::cpumap();
17 // These are future proofing, trace doesn't actually need page alignment
18 // here, just file block size alignment. When page sizes go to 16k, we
19 // don't want 16k of padding.
21 #define FILE_BLOCK_SIZE 4096
22 #define FILE_BLOCK_SIZE_MASK 4095
25 * To write a RAW_VERSION1+ file, we must embed a cpumap in the "padding"
26 * used to file block align the events folloing the threadmap. If the
27 * threadmap happens to not require enough padding, we artificially
28 * increase its footprint until it needs enough padding.
31 uint32_t pad_size
= FILE_BLOCK_SIZE
- ((sizeof(TraceDataHeader
<SIZE
>) + (threadmap
.size() * sizeof(KDThreadMapEntry
<SIZE
>))) & FILE_BLOCK_SIZE_MASK
);
32 uint32_t cpumap_size
= sizeof(kd_cpumap_header
) + (uint32_t)cpumap
.size() * sizeof(KDCPUMapEntry
);
33 uint32_t extra_thread_count
= 0;
35 if (cpumap_size
> pad_size
) {
36 /* Force an overflow onto the next page, we get a full page of padding */
37 extra_thread_count
= (pad_size
/ sizeof(KDCPUMapEntry
)) + 1;
41 TraceDataHeader
<SIZE
> header(RAW_VERSION1
, (uint32_t)threadmap
.size(), time(NULL
), 0);
42 write(save_fd
, &header
, sizeof(TraceDataHeader
<SIZE
>));
44 // Write the threadmaps
45 write(save_fd
, threadmap
.data(), threadmap
.size() * sizeof(KDThreadMapEntry
<SIZE
>));
47 if (extra_thread_count
) {
48 pad_size
= extra_thread_count
* sizeof(KDThreadMapEntry
<SIZE
>);
49 auto pad_buf
= (uint8_t *)calloc(pad_size
, 1);
50 write(save_fd
, pad_buf
, pad_size
);
54 // Write the cpumaps & any remaining padding
55 size_t bytes_written
= sizeof(TraceDataHeader
<SIZE
>) + (threadmap
.size() + extra_thread_count
) * sizeof(KDThreadMapEntry
<SIZE
>);
56 pad_size
= FILE_BLOCK_SIZE
- (bytes_written
& FILE_BLOCK_SIZE_MASK
);
58 ASSERT(pad_size
>= cpumap
.size() * sizeof(KDCPUMapEntry
), "Not enough padding bytes!");
60 auto cpumap_header
= (kd_cpumap_header
*)calloc(pad_size
, 1);
61 cpumap_header
->version_no
= RAW_VERSION1
;
62 cpumap_header
->cpu_count
= (uint32_t)cpumap
.size();
63 auto cpus
= (kd_cpumap
*)&cpumap_header
[1];
64 memcpy(cpus
, cpumap
.data(), cpumap
.size() * sizeof(KDCPUMapEntry
));
65 write(save_fd
, cpumap_header
, pad_size
);
70 // Because this may be used to capture boot traces which consume very
71 // large amounts of memory, we will likely not be able to collect
72 // the entire buffer space in a single shot. Read it in small chunks.
74 auto twenty_mb
= 20 * 1024 * 1024;
75 auto num_events_in_twenty_mb
= twenty_mb
/ sizeof(KDEvent
<SIZE
>);
76 MemoryBuffer
<KDEvent
<SIZE
>> events(num_events_in_twenty_mb
);
78 // We read until we don't get back a full buffer, hoping thats enough.
80 int count
= KDBG::read(events
.data(), events
.capacity_in_bytes());
83 write(save_fd
, events
.data(), count
* sizeof(KDEvent
<SIZE
>));
85 if (count
< num_events_in_twenty_mb
) {
94 void SaveTraceAction::execute(Globals
& globals
) {
95 KDState state
= KDBG::state();
96 if (state
.is_lp64()) {
97 execute_arch_specific
<Kernel64
>(globals
, state
, _save_fd
);
99 execute_arch_specific
<Kernel32
>(globals
, state
, _save_fd
);