1 // Test whether mmap'ing profile counters onto an open file is feasible. As
2 // this involves some platform-specific logic, this test is designed to be a
3 // minimum viable proof-of-concept: it may be useful when porting the mmap()
4 // mode to a new platform, but is not in and of itself a test of the profiling
9 // Align counters and data to the maximum expected page size (16K).
10 // RUN: %clang -g -o %t %s \
11 // RUN: -Wl,-sectalign,__DATA,__pcnts,0x4000 \
12 // RUN: -Wl,-sectalign,__DATA,__pdata,0x4000
14 // Create a 'profile' using mmap() and validate it.
15 // RUN: %run %t create %t.tmpfile
16 // RUN: %run %t validate %t.tmpfile
25 __attribute__((section("__DATA,__pcnts"))) int counters
[] = {0xbad};
26 extern int cnts_start
__asm("section$start$__DATA$__pcnts");
27 const size_t cnts_len
= 0x4000;
29 __attribute__((section("__DATA,__pdata"))) int data
[] = {1, 2, 3};
30 extern int data_start
__asm("section$start$__DATA$__pdata");
31 const size_t data_len
= sizeof(int) * 3;
33 int create_tmpfile(char *path
) {
34 // Create a temp file.
35 int fd
= open(path
, O_RDWR
| O_TRUNC
| O_CREAT
, 0666);
41 // Grow the file to hold data and counters.
42 if (0 != ftruncate(fd
, cnts_len
+ data_len
)) {
47 // Write the data first (at offset 0x4000, after the counters).
48 if (data_len
!= pwrite(fd
, &data
, data_len
, 0x4000)) {
53 // Map the counters into the file, before the data.
55 // Requirements (on Darwin):
56 // - &cnts_start must be page-aligned.
57 // - The length and offset-into-fd must be page-aligned.
58 int *counter_map
= (int *)mmap(&cnts_start
, 0x4000, PROT_READ
| PROT_WRITE
,
59 MAP_FIXED
| MAP_SHARED
, fd
, 0);
60 if (counter_map
!= &cnts_start
) {
65 // Update counters 1..9. These updates should be visible in the file.
66 // Expect counter 0 (0xbad), which is not updated, to be zero in the file.
67 for (int i
= 1; i
< 10; ++i
)
70 // Intentionally do not msync(), munmap(), or close().
74 int validate_tmpfile(char *path
) {
75 int fd
= open(path
, O_RDONLY
);
81 // Verify that the file length is: sizeof(counters) + sizeof(data).
82 const size_t num_bytes
= cnts_len
+ data_len
;
84 if (num_bytes
!= read(fd
, &buf
, num_bytes
)) {
89 // Verify the values of counters 1..9 (i.e. that the mmap() worked).
90 for (int i
= 0; i
< 10; ++i
) {
93 "validate_tmpfile: Expected '%d' at pos=%d, but got '%d' instead.\n",
99 // Verify that the rest of the counters (after counter 9) are 0.
100 const int num_cnts
= 0x4000 / sizeof(int);
101 for (int i
= 10; i
< num_cnts
; ++i
) {
104 "validate_tmpfile: Expected '%d' at pos=%d, but got '%d' instead.\n",
110 // Verify that the data written after the counters is equal to the "data[]"
111 // array (i.e. {1, 2, 3}).
112 for (int i
= num_cnts
; i
< num_cnts
+ 3; ++i
) {
113 if (buf
[i
] != (i
- num_cnts
+ 1)) {
115 "validate_tmpfile: Expected '%d' at pos=%d, but got '%d' instead.\n",
116 i
- num_cnts
+ 1, i
, buf
[i
]);
121 // Intentionally do not close().
125 int main(int argc
, char **argv
) {
126 intptr_t cnts_start_int
= (intptr_t)&cnts_start
;
127 intptr_t data_start_int
= (intptr_t)&data_start
;
128 int pagesz
= getpagesize();
130 if (cnts_start_int
% pagesz
!= 0) {
131 fprintf(stderr
, "__pcnts is not page-aligned: 0x%lx.\n", cnts_start_int
);
134 if (data_start_int
% pagesz
!= 0) {
135 fprintf(stderr
, "__pdata is not page-aligned: 0x%lx.\n", data_start_int
);
138 if (cnts_start_int
+ 0x4000 != data_start_int
) {
139 fprintf(stderr
, "__pdata not ordered after __pcnts.\n");
143 char *action
= argv
[1];
144 char *path
= argv
[2];
145 if (0 == strcmp(action
, "create"))
146 return create_tmpfile(path
);
147 else if (0 == strcmp(action
, "validate"))
148 return validate_tmpfile(path
);