blob: 1bd2af323b91f115bfbb4e22769441b818d1401d [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. */
30 uint64_t Header[PROFILE_HEADER_SIZE] = {
31 __llvm_profile_get_magic(),
32 __llvm_profile_get_version(),
33 DataSize,
34 CountersSize,
35 NamesSize,
36 (uint64_t)CountersBegin,
37 (uint64_t)NamesBegin
38 };
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000039
40 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000041#define CHECK_fwrite(Data, Size, Length, File) \
42 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
43 CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
44 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000045 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000046 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000047#undef CHECK_fwrite
48
49 return 0;
50}
51
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000052static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000053 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000054 FILE *OutputFile;
55 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000056 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000057 OutputFile = fopen(OutputName, "w");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000058 if (!OutputFile)
59 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000060
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000061 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000062
63 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000064 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000065}
66
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000067static const char *CurrentFilename = NULL;
Duncan P. N. Exon Smith9edbae02014-03-20 20:00:44 +000068void __llvm_profile_set_filename(const char *Filename) {
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000069 CurrentFilename = Filename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000070}
71
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000072int getpid(void);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000073int __llvm_profile_write_file(void) {
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000074 char *AllocatedFilename = NULL;
75 int I, J;
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000076 int RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000077
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000078#define MAX_PID_SIZE 16
79 char PidChars[MAX_PID_SIZE] = { 0 };
80 int PidLength = 0;
81 int NumPids = 0;
82
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000083 /* Get the filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000084 const char *Filename = CurrentFilename;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +000085#define UPDATE_FILENAME(NextFilename) \
86 if (!Filename || !Filename[0]) Filename = NextFilename
87 UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
88 UPDATE_FILENAME("default.profdata");
89#undef UPDATE_FILENAME
90
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000091 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000092 for (I = 0; Filename[I]; ++I)
93 if (Filename[I] == '%' && Filename[++I] == 'p')
94 if (!NumPids++) {
95 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
96 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000097 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000098 }
99 if (NumPids) {
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000100 /* Allocate enough space for the substituted filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000101 AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
102 if (!AllocatedFilename)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000103 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000104
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000105 /* Construct the new filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000106 for (I = 0, J = 0; Filename[I]; ++I)
107 if (Filename[I] == '%') {
108 if (Filename[++I] == 'p') {
109 memcpy(AllocatedFilename + J, PidChars, PidLength);
110 J += PidLength;
111 }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000112 /* Drop any unknown substitutions. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000113 } else
114 AllocatedFilename[J++] = Filename[I];
115 AllocatedFilename[J] = 0;
116
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000117 /* Actually use the computed name. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000118 Filename = AllocatedFilename;
119 }
120
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000121 /* Write the file. */
122 RetVal = writeFileWithName(Filename);
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000123
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000124 /* Free the filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000125 if (AllocatedFilename)
126 free(AllocatedFilename);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000127
128 return RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000129}
130
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000131static void writeFileWithoutReturn(void) {
132 __llvm_profile_write_file();
133}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000134
135int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000136 static int HasBeenRegistered = 0;
137
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000138 if (HasBeenRegistered)
139 return 0;
140
141 HasBeenRegistered = 1;
142 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000143}