blob: 2c40ca5af4f2cd4ff62e649936ead34d1bd71283 [file] [log] [blame]
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +00001/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +00002|*
3|* The LLVM Compiler Infrastructure
4|*
5|* This file is distributed under the University of Illinois Open Source
6|* License. See LICENSE.TXT for details.
7|*
8\*===----------------------------------------------------------------------===*/
9
10#include "InstrProfiling.h"
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000011#include <stdio.h>
12#include <stdlib.h>
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000013#include <string.h>
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000014
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000015static int writeFile(FILE *File) {
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000016 /* Match logic in __llvm_profile_write_buffer(). */
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000017 const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
18 const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
19 const uint64_t *CountersBegin = __llvm_profile_counters_begin();
20 const uint64_t *CountersEnd = __llvm_profile_counters_end();
21 const char *NamesBegin = __llvm_profile_names_begin();
22 const char *NamesEnd = __llvm_profile_names_end();
23
24 /* Calculate size of sections. */
25 const uint64_t DataSize = DataEnd - DataBegin;
26 const uint64_t CountersSize = CountersEnd - CountersBegin;
27 const uint64_t NamesSize = NamesEnd - NamesBegin;
28
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000029 /* Create the header. */
Reid Kleckneraf6b2502014-05-01 18:52:14 +000030 uint64_t Header[PROFILE_HEADER_SIZE];
31 Header[0] = __llvm_profile_get_magic();
32 Header[1] = __llvm_profile_get_version();
33 Header[2] = DataSize;
34 Header[3] = CountersSize;
35 Header[4] = NamesSize;
36 Header[5] = (uintptr_t)CountersBegin;
37 Header[6] = (uintptr_t)NamesBegin;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000038
39 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000040#define CHECK_fwrite(Data, Size, Length, File) \
41 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
42 CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
43 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000044 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000045 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000046#undef CHECK_fwrite
47
48 return 0;
49}
50
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000051static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000052 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000053 FILE *OutputFile;
54 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000055 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000056 OutputFile = fopen(OutputName, "w");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000057 if (!OutputFile)
58 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000059
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000060 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000061
62 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000063 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000064}
65
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000066static const char *CurrentFilename = NULL;
Duncan P. N. Exon Smith9edbae02014-03-20 20:00:44 +000067void __llvm_profile_set_filename(const char *Filename) {
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000068 CurrentFilename = Filename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000069}
70
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000071int getpid(void);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000072int __llvm_profile_write_file(void) {
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000073 char *AllocatedFilename = NULL;
74 int I, J;
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000075 int RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000076
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000077#define MAX_PID_SIZE 16
78 char PidChars[MAX_PID_SIZE] = { 0 };
79 int PidLength = 0;
80 int NumPids = 0;
81
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000082 /* Get the filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000083 const char *Filename = CurrentFilename;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000084#define UPDATE_FILENAME(NextFilename) \
85 if (!Filename || !Filename[0]) Filename = NextFilename
86 UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
Duncan P. N. Exon Smith21b98a62014-03-24 21:53:42 +000087 UPDATE_FILENAME("default.profraw");
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000088#undef UPDATE_FILENAME
89
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000090 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000091 for (I = 0; Filename[I]; ++I)
92 if (Filename[I] == '%' && Filename[++I] == 'p')
93 if (!NumPids++) {
94 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
95 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000096 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000097 }
98 if (NumPids) {
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000099 /* Allocate enough space for the substituted filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000100 AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
101 if (!AllocatedFilename)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000102 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000103
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000104 /* Construct the new filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000105 for (I = 0, J = 0; Filename[I]; ++I)
106 if (Filename[I] == '%') {
107 if (Filename[++I] == 'p') {
108 memcpy(AllocatedFilename + J, PidChars, PidLength);
109 J += PidLength;
110 }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000111 /* Drop any unknown substitutions. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000112 } else
113 AllocatedFilename[J++] = Filename[I];
114 AllocatedFilename[J] = 0;
115
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000116 /* Actually use the computed name. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000117 Filename = AllocatedFilename;
118 }
119
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000120 /* Write the file. */
121 RetVal = writeFileWithName(Filename);
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000122
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000123 /* Free the filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000124 if (AllocatedFilename)
125 free(AllocatedFilename);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000126
127 return RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000128}
129
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000130static void writeFileWithoutReturn(void) {
131 __llvm_profile_write_file();
132}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000133
134int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000135 static int HasBeenRegistered = 0;
136
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000137 if (HasBeenRegistered)
138 return 0;
139
140 HasBeenRegistered = 1;
141 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000142}