1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ 2 |* 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" 11 #include "InstrProfilingInternal.h" 12 #include "InstrProfilingUtil.h" 13 #include <errno.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #ifdef _MSC_VER 18 /* For _alloca. */ 19 #include <malloc.h> 20 #endif 21 #if defined(_WIN32) 22 #include "WindowsMMap.h" 23 /* For _chsize_s */ 24 #include <io.h> 25 #else 26 #include <sys/file.h> 27 #include <sys/mman.h> 28 #include <unistd.h> 29 #if defined(__linux__) 30 #include <sys/types.h> 31 #endif 32 #endif 33 34 /* From where is profile name specified. 35 * The order the enumerators define their 36 * precedence. Re-order them may lead to 37 * runtime behavior change. */ 38 typedef enum ProfileNameSpecifier { 39 PNS_unknown = 0, 40 PNS_default, 41 PNS_command_line, 42 PNS_environment, 43 PNS_runtime_api 44 } ProfileNameSpecifier; 45 46 static const char *getPNSStr(ProfileNameSpecifier PNS) { 47 switch (PNS) { 48 case PNS_default: 49 return "default setting"; 50 case PNS_command_line: 51 return "command line"; 52 case PNS_environment: 53 return "environment variable"; 54 case PNS_runtime_api: 55 return "runtime API"; 56 default: 57 return "Unknown"; 58 } 59 } 60 61 #define MAX_PID_SIZE 16 62 /* Data structure holding the result of parsed filename pattern. */ 63 typedef struct lprofFilename { 64 /* File name string possibly with %p or %h specifiers. */ 65 const char *FilenamePat; 66 char PidChars[MAX_PID_SIZE]; 67 char Hostname[COMPILER_RT_MAX_HOSTLEN]; 68 unsigned NumPids; 69 unsigned NumHosts; 70 /* When in-process merging is enabled, this parameter specifies 71 * the total number of profile data files shared by all the processes 72 * spawned from the same binary. By default the value is 1. If merging 73 * is not enabled, its value should be 0. This parameter is specified 74 * by the %[0-9]m specifier. For instance %2m enables merging using 75 * 2 profile data files. %1m is equivalent to %m. Also %m specifier 76 * can only appear once at the end of the name pattern. */ 77 unsigned MergePoolSize; 78 ProfileNameSpecifier PNS; 79 } lprofFilename; 80 81 lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0, 0, PNS_unknown}; 82 83 int getpid(void); 84 static int getCurFilenameLength(); 85 static const char *getCurFilename(char *FilenameBuf); 86 static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } 87 88 /* Return 1 if there is an error, otherwise return 0. */ 89 static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, 90 void **WriterCtx) { 91 uint32_t I; 92 FILE *File = (FILE *)*WriterCtx; 93 for (I = 0; I < NumIOVecs; I++) { 94 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 95 IOVecs[I].NumElm) 96 return 1; 97 } 98 return 0; 99 } 100 101 COMPILER_RT_VISIBILITY ProfBufferIO * 102 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 103 FreeHook = &free; 104 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 105 VPBufferSize = BufferSz; 106 return lprofCreateBufferIO(fileWriter, File); 107 } 108 109 static void setupIOBuffer() { 110 const char *BufferSzStr = 0; 111 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 112 if (BufferSzStr && BufferSzStr[0]) { 113 VPBufferSize = atoi(BufferSzStr); 114 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 115 } 116 } 117 118 /* Read profile data in \c ProfileFile and merge with in-memory 119 profile counters. Returns -1 if there is fatal error, otheriwse 120 0 is returned. 121 */ 122 static int doProfileMerging(FILE *ProfileFile) { 123 uint64_t ProfileFileSize; 124 char *ProfileBuffer; 125 126 if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 127 PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 128 strerror(errno)); 129 return -1; 130 } 131 ProfileFileSize = ftell(ProfileFile); 132 133 /* Restore file offset. */ 134 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 135 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 136 strerror(errno)); 137 return -1; 138 } 139 140 /* Nothing to merge. */ 141 if (ProfileFileSize < sizeof(__llvm_profile_header)) { 142 if (ProfileFileSize) 143 PROF_WARN("Unable to merge profile data: %s\n", 144 "source profile file is too small."); 145 return 0; 146 } 147 148 ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 149 fileno(ProfileFile), 0); 150 if (ProfileBuffer == MAP_FAILED) { 151 PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 152 strerror(errno)); 153 return -1; 154 } 155 156 if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 157 (void)munmap(ProfileBuffer, ProfileFileSize); 158 PROF_WARN("Unable to merge profile data: %s\n", 159 "source profile file is not compatible."); 160 return 0; 161 } 162 163 /* Now start merging */ 164 __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 165 (void)munmap(ProfileBuffer, ProfileFileSize); 166 167 return 0; 168 } 169 170 /* Open the profile data for merging. It opens the file in r+b mode with 171 * file locking. If the file has content which is compatible with the 172 * current process, it also reads in the profile data in the file and merge 173 * it with in-memory counters. After the profile data is merged in memory, 174 * the original profile data is truncated and gets ready for the profile 175 * dumper. With profile merging enabled, each executable as well as any of 176 * its instrumented shared libraries dump profile data into their own data file. 177 */ 178 static FILE *openFileForMerging(const char *ProfileFileName) { 179 FILE *ProfileFile; 180 int rc; 181 182 ProfileFile = lprofOpenFileEx(ProfileFileName); 183 if (!ProfileFile) 184 return NULL; 185 186 rc = doProfileMerging(ProfileFile); 187 if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || 188 fseek(ProfileFile, 0L, SEEK_SET) == -1) { 189 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 190 strerror(errno)); 191 fclose(ProfileFile); 192 return NULL; 193 } 194 fseek(ProfileFile, 0L, SEEK_SET); 195 return ProfileFile; 196 } 197 198 /* Write profile data to file \c OutputName. */ 199 static int writeFile(const char *OutputName) { 200 int RetVal; 201 FILE *OutputFile; 202 203 if (!doMerging()) 204 OutputFile = fopen(OutputName, "ab"); 205 else 206 OutputFile = openFileForMerging(OutputName); 207 208 if (!OutputFile) 209 return -1; 210 211 FreeHook = &free; 212 setupIOBuffer(); 213 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); 214 215 fclose(OutputFile); 216 return RetVal; 217 } 218 219 static void truncateCurrentFile(void) { 220 const char *Filename; 221 char *FilenameBuf; 222 FILE *File; 223 int Length; 224 225 Length = getCurFilenameLength(); 226 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 227 Filename = getCurFilename(FilenameBuf); 228 if (!Filename) 229 return; 230 231 /* Create the directory holding the file, if needed. */ 232 if (strchr(Filename, DIR_SEPARATOR) 233 #if defined(DIR_SEPARATOR_2) 234 || strchr(Filename, DIR_SEPARATOR_2) 235 #endif 236 ) { 237 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 238 strncpy(Copy, Filename, Length + 1); 239 __llvm_profile_recursive_mkdir(Copy); 240 } 241 242 /* Truncate the file. Later we'll reopen and append. */ 243 File = fopen(Filename, "w"); 244 if (!File) 245 return; 246 fclose(File); 247 } 248 249 static const char *DefaultProfileName = "default.profraw"; 250 static void resetFilenameToDefault(void) { 251 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 252 lprofCurFilename.FilenamePat = DefaultProfileName; 253 lprofCurFilename.PNS = PNS_default; 254 } 255 256 static int containsMergeSpecifier(const char *FilenamePat, int I) { 257 return (FilenamePat[I] == 'm' || 258 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 259 /* If FilenamePat[I] is not '\0', the next byte is guaranteed 260 * to be in-bound as the string is null terminated. */ 261 FilenamePat[I + 1] == 'm')); 262 } 263 264 /* Parses the pattern string \p FilenamePat and stores the result to 265 * lprofcurFilename structure. */ 266 static int parseFilenamePattern(const char *FilenamePat) { 267 int NumPids = 0, NumHosts = 0, I; 268 char *PidChars = &lprofCurFilename.PidChars[0]; 269 char *Hostname = &lprofCurFilename.Hostname[0]; 270 int MergingEnabled = 0; 271 272 lprofCurFilename.FilenamePat = FilenamePat; 273 /* Check the filename for "%p", which indicates a pid-substitution. */ 274 for (I = 0; FilenamePat[I]; ++I) 275 if (FilenamePat[I] == '%') { 276 if (FilenamePat[++I] == 'p') { 277 if (!NumPids++) { 278 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { 279 PROF_WARN( 280 "Unable to parse filename pattern %s. Using the default name.", 281 FilenamePat); 282 return -1; 283 } 284 } 285 } else if (FilenamePat[I] == 'h') { 286 if (!NumHosts++) 287 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 288 PROF_WARN( 289 "Unable to parse filename pattern %s. Using the default name.", 290 FilenamePat); 291 return -1; 292 } 293 } else if (containsMergeSpecifier(FilenamePat, I)) { 294 if (MergingEnabled) { 295 PROF_WARN("%%m specifier can only be specified once in %s.\n", 296 FilenamePat); 297 return -1; 298 } 299 MergingEnabled = 1; 300 if (FilenamePat[I] == 'm') 301 lprofCurFilename.MergePoolSize = 1; 302 else { 303 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 304 I++; /* advance to 'm' */ 305 } 306 } 307 } 308 309 lprofCurFilename.NumPids = NumPids; 310 lprofCurFilename.NumHosts = NumHosts; 311 return 0; 312 } 313 314 static void parseAndSetFilename(const char *FilenamePat, 315 ProfileNameSpecifier PNS) { 316 317 const char *OldFilenamePat = lprofCurFilename.FilenamePat; 318 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 319 320 if (PNS < OldPNS) 321 return; 322 323 if (!FilenamePat) 324 FilenamePat = DefaultProfileName; 325 326 /* When -fprofile-instr-generate=<path> is specified on the 327 * command line, each module will be instrumented with runtime 328 * init call to __llvm_profile_init function which calls 329 * __llvm_profile_override_default_filename. In most of the cases, 330 * the path will be identical, so bypass the parsing completely. 331 */ 332 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 333 lprofCurFilename.PNS = PNS; 334 return; 335 } 336 337 /* When PNS >= OldPNS, the last one wins. */ 338 if (!FilenamePat || parseFilenamePattern(FilenamePat)) 339 resetFilenameToDefault(); 340 lprofCurFilename.PNS = PNS; 341 342 if (!OldFilenamePat) { 343 PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 344 lprofCurFilename.FilenamePat, getPNSStr(PNS)); 345 } else { 346 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 347 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 348 getPNSStr(PNS)); 349 } 350 351 if (!lprofCurFilename.MergePoolSize) 352 truncateCurrentFile(); 353 } 354 355 /* Return buffer length that is required to store the current profile 356 * filename with PID and hostname substitutions. */ 357 /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 358 #define SIGLEN 24 359 static int getCurFilenameLength() { 360 int Len; 361 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 362 return 0; 363 364 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 365 lprofCurFilename.MergePoolSize)) 366 return strlen(lprofCurFilename.FilenamePat); 367 368 Len = strlen(lprofCurFilename.FilenamePat) + 369 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 370 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 371 if (lprofCurFilename.MergePoolSize) 372 Len += SIGLEN; 373 return Len; 374 } 375 376 /* Return the pointer to the current profile file name (after substituting 377 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 378 * to store the resulting filename. If no substitution is needed, the 379 * current filename pattern string is directly returned. */ 380 static const char *getCurFilename(char *FilenameBuf) { 381 int I, J, PidLength, HostNameLength; 382 const char *FilenamePat = lprofCurFilename.FilenamePat; 383 384 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 385 return 0; 386 387 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 388 lprofCurFilename.MergePoolSize)) 389 return lprofCurFilename.FilenamePat; 390 391 PidLength = strlen(lprofCurFilename.PidChars); 392 HostNameLength = strlen(lprofCurFilename.Hostname); 393 /* Construct the new filename. */ 394 for (I = 0, J = 0; FilenamePat[I]; ++I) 395 if (FilenamePat[I] == '%') { 396 if (FilenamePat[++I] == 'p') { 397 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 398 J += PidLength; 399 } else if (FilenamePat[I] == 'h') { 400 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 401 J += HostNameLength; 402 } else if (containsMergeSpecifier(FilenamePat, I)) { 403 char LoadModuleSignature[SIGLEN]; 404 int S; 405 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 406 S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 407 lprofGetLoadModuleSignature(), ProfilePoolId); 408 if (S == -1 || S > SIGLEN) 409 S = SIGLEN; 410 memcpy(FilenameBuf + J, LoadModuleSignature, S); 411 J += S; 412 if (FilenamePat[I] != 'm') 413 I++; 414 } 415 /* Drop any unknown substitutions. */ 416 } else 417 FilenameBuf[J++] = FilenamePat[I]; 418 FilenameBuf[J] = 0; 419 420 return FilenameBuf; 421 } 422 423 /* Returns the pointer to the environment variable 424 * string. Returns null if the env var is not set. */ 425 static const char *getFilenamePatFromEnv(void) { 426 const char *Filename = getenv("LLVM_PROFILE_FILE"); 427 if (!Filename || !Filename[0]) 428 return 0; 429 return Filename; 430 } 431 432 /* This method is invoked by the runtime initialization hook 433 * InstrProfilingRuntime.o if it is linked in. Both user specified 434 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 435 * environment variable can override this default value. */ 436 COMPILER_RT_VISIBILITY 437 void __llvm_profile_initialize_file(void) { 438 const char *FilenamePat; 439 440 FilenamePat = getFilenamePatFromEnv(); 441 parseAndSetFilename(FilenamePat, FilenamePat ? PNS_environment : PNS_default); 442 } 443 444 /* This API is directly called by the user application code. It has the 445 * highest precedence compared with LLVM_PROFILE_FILE environment variable 446 * and command line option -fprofile-instr-generate=<profile_name>. 447 */ 448 COMPILER_RT_VISIBILITY 449 void __llvm_profile_set_filename(const char *FilenamePat) { 450 parseAndSetFilename(FilenamePat, PNS_runtime_api); 451 } 452 453 /* 454 * This API is invoked by the global initializers emitted by Clang/LLVM when 455 * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate 456 * without an argument). This option has lower precedence than the 457 * LLVM_PROFILE_FILE environment variable. 458 */ 459 COMPILER_RT_VISIBILITY 460 void __llvm_profile_override_default_filename(const char *FilenamePat) { 461 parseAndSetFilename(FilenamePat, PNS_command_line); 462 } 463 464 /* The public API for writing profile data into the file with name 465 * set by previous calls to __llvm_profile_set_filename or 466 * __llvm_profile_override_default_filename or 467 * __llvm_profile_initialize_file. */ 468 COMPILER_RT_VISIBILITY 469 int __llvm_profile_write_file(void) { 470 int rc, Length; 471 const char *Filename; 472 char *FilenameBuf; 473 474 Length = getCurFilenameLength(); 475 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 476 Filename = getCurFilename(FilenameBuf); 477 478 /* Check the filename. */ 479 if (!Filename) { 480 PROF_ERR("Failed to write file : %s\n", "Filename not set"); 481 return -1; 482 } 483 484 /* Check if there is llvm/runtime version mismatch. */ 485 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 486 PROF_ERR("Runtime and instrumentation version mismatch : " 487 "expected %d, but get %d\n", 488 INSTR_PROF_RAW_VERSION, 489 (int)GET_VERSION(__llvm_profile_get_version())); 490 return -1; 491 } 492 493 /* Write profile data to the file. */ 494 rc = writeFile(Filename); 495 if (rc) 496 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 497 return rc; 498 } 499 500 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 501 502 COMPILER_RT_VISIBILITY 503 int __llvm_profile_register_write_file_atexit(void) { 504 static int HasBeenRegistered = 0; 505 506 if (HasBeenRegistered) 507 return 0; 508 509 lprofSetupValueProfiler(); 510 511 HasBeenRegistered = 1; 512 return atexit(writeFileWithoutReturn); 513 } 514