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 /* A flag indicating if FilenamePat's memory is allocated 67 * by runtime. */ 68 unsigned OwnsFilenamePat; 69 const char *ProfilePathPrefix; 70 char PidChars[MAX_PID_SIZE]; 71 char Hostname[COMPILER_RT_MAX_HOSTLEN]; 72 unsigned NumPids; 73 unsigned NumHosts; 74 /* When in-process merging is enabled, this parameter specifies 75 * the total number of profile data files shared by all the processes 76 * spawned from the same binary. By default the value is 1. If merging 77 * is not enabled, its value should be 0. This parameter is specified 78 * by the %[0-9]m specifier. For instance %2m enables merging using 79 * 2 profile data files. %1m is equivalent to %m. Also %m specifier 80 * can only appear once at the end of the name pattern. */ 81 unsigned MergePoolSize; 82 ProfileNameSpecifier PNS; 83 } lprofFilename; 84 85 COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, 86 0, 0, 0, PNS_unknown}; 87 88 int getpid(void); 89 static int getCurFilenameLength(); 90 static const char *getCurFilename(char *FilenameBuf); 91 static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } 92 93 /* Return 1 if there is an error, otherwise return 0. */ 94 static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, 95 void **WriterCtx) { 96 uint32_t I; 97 FILE *File = (FILE *)*WriterCtx; 98 for (I = 0; I < NumIOVecs; I++) { 99 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 100 IOVecs[I].NumElm) 101 return 1; 102 } 103 return 0; 104 } 105 106 COMPILER_RT_VISIBILITY ProfBufferIO * 107 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 108 FreeHook = &free; 109 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 110 VPBufferSize = BufferSz; 111 return lprofCreateBufferIO(fileWriter, File); 112 } 113 114 static void setupIOBuffer() { 115 const char *BufferSzStr = 0; 116 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 117 if (BufferSzStr && BufferSzStr[0]) { 118 VPBufferSize = atoi(BufferSzStr); 119 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 120 } 121 } 122 123 /* Read profile data in \c ProfileFile and merge with in-memory 124 profile counters. Returns -1 if there is fatal error, otheriwse 125 0 is returned. 126 */ 127 static int doProfileMerging(FILE *ProfileFile) { 128 uint64_t ProfileFileSize; 129 char *ProfileBuffer; 130 131 if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 132 PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 133 strerror(errno)); 134 return -1; 135 } 136 ProfileFileSize = ftell(ProfileFile); 137 138 /* Restore file offset. */ 139 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 140 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 141 strerror(errno)); 142 return -1; 143 } 144 145 /* Nothing to merge. */ 146 if (ProfileFileSize < sizeof(__llvm_profile_header)) { 147 if (ProfileFileSize) 148 PROF_WARN("Unable to merge profile data: %s\n", 149 "source profile file is too small."); 150 return 0; 151 } 152 153 ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 154 fileno(ProfileFile), 0); 155 if (ProfileBuffer == MAP_FAILED) { 156 PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 157 strerror(errno)); 158 return -1; 159 } 160 161 if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 162 (void)munmap(ProfileBuffer, ProfileFileSize); 163 PROF_WARN("Unable to merge profile data: %s\n", 164 "source profile file is not compatible."); 165 return 0; 166 } 167 168 /* Now start merging */ 169 __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 170 (void)munmap(ProfileBuffer, ProfileFileSize); 171 172 return 0; 173 } 174 175 /* Create the directory holding the file, if needed. */ 176 static void createProfileDir(const char *Filename) { 177 size_t Length = strlen(Filename); 178 if (lprofFindFirstDirSeparator(Filename)) { 179 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 180 strncpy(Copy, Filename, Length + 1); 181 __llvm_profile_recursive_mkdir(Copy); 182 } 183 } 184 185 /* Open the profile data for merging. It opens the file in r+b mode with 186 * file locking. If the file has content which is compatible with the 187 * current process, it also reads in the profile data in the file and merge 188 * it with in-memory counters. After the profile data is merged in memory, 189 * the original profile data is truncated and gets ready for the profile 190 * dumper. With profile merging enabled, each executable as well as any of 191 * its instrumented shared libraries dump profile data into their own data file. 192 */ 193 static FILE *openFileForMerging(const char *ProfileFileName) { 194 FILE *ProfileFile; 195 int rc; 196 197 createProfileDir(ProfileFileName); 198 ProfileFile = lprofOpenFileEx(ProfileFileName); 199 if (!ProfileFile) 200 return NULL; 201 202 rc = doProfileMerging(ProfileFile); 203 if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || 204 fseek(ProfileFile, 0L, SEEK_SET) == -1) { 205 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 206 strerror(errno)); 207 fclose(ProfileFile); 208 return NULL; 209 } 210 fseek(ProfileFile, 0L, SEEK_SET); 211 return ProfileFile; 212 } 213 214 /* Write profile data to file \c OutputName. */ 215 static int writeFile(const char *OutputName) { 216 int RetVal; 217 FILE *OutputFile; 218 219 if (!doMerging()) 220 OutputFile = fopen(OutputName, "ab"); 221 else 222 OutputFile = openFileForMerging(OutputName); 223 224 if (!OutputFile) 225 return -1; 226 227 FreeHook = &free; 228 setupIOBuffer(); 229 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); 230 231 fclose(OutputFile); 232 return RetVal; 233 } 234 235 static void truncateCurrentFile(void) { 236 const char *Filename; 237 char *FilenameBuf; 238 FILE *File; 239 int Length; 240 241 Length = getCurFilenameLength(); 242 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 243 Filename = getCurFilename(FilenameBuf); 244 if (!Filename) 245 return; 246 247 /* By pass file truncation to allow online raw profile 248 * merging. */ 249 if (lprofCurFilename.MergePoolSize) 250 return; 251 252 createProfileDir(Filename); 253 254 /* Truncate the file. Later we'll reopen and append. */ 255 File = fopen(Filename, "w"); 256 if (!File) 257 return; 258 fclose(File); 259 } 260 261 static const char *DefaultProfileName = "default.profraw"; 262 static void resetFilenameToDefault(void) { 263 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 264 free((void *)lprofCurFilename.FilenamePat); 265 } 266 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 267 lprofCurFilename.FilenamePat = DefaultProfileName; 268 lprofCurFilename.PNS = PNS_default; 269 } 270 271 static int containsMergeSpecifier(const char *FilenamePat, int I) { 272 return (FilenamePat[I] == 'm' || 273 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 274 /* If FilenamePat[I] is not '\0', the next byte is guaranteed 275 * to be in-bound as the string is null terminated. */ 276 FilenamePat[I + 1] == 'm')); 277 } 278 279 /* Parses the pattern string \p FilenamePat and stores the result to 280 * lprofcurFilename structure. */ 281 static int parseFilenamePattern(const char *FilenamePat, 282 unsigned CopyFilenamePat) { 283 int NumPids = 0, NumHosts = 0, I; 284 char *PidChars = &lprofCurFilename.PidChars[0]; 285 char *Hostname = &lprofCurFilename.Hostname[0]; 286 int MergingEnabled = 0; 287 288 /* Clean up cached prefix. */ 289 if (lprofCurFilename.ProfilePathPrefix) 290 free((void *)lprofCurFilename.ProfilePathPrefix); 291 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 292 293 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 294 free((void *)lprofCurFilename.FilenamePat); 295 } 296 297 if (!CopyFilenamePat) 298 lprofCurFilename.FilenamePat = FilenamePat; 299 else { 300 lprofCurFilename.FilenamePat = strdup(FilenamePat); 301 lprofCurFilename.OwnsFilenamePat = 1; 302 } 303 /* Check the filename for "%p", which indicates a pid-substitution. */ 304 for (I = 0; FilenamePat[I]; ++I) 305 if (FilenamePat[I] == '%') { 306 if (FilenamePat[++I] == 'p') { 307 if (!NumPids++) { 308 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { 309 PROF_WARN("Unable to get pid for filename pattern %s. Using the " 310 "default name.", 311 FilenamePat); 312 return -1; 313 } 314 } 315 } else if (FilenamePat[I] == 'h') { 316 if (!NumHosts++) 317 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 318 PROF_WARN("Unable to get hostname for filename pattern %s. Using " 319 "the default name.", 320 FilenamePat); 321 return -1; 322 } 323 } else if (containsMergeSpecifier(FilenamePat, I)) { 324 if (MergingEnabled) { 325 PROF_WARN("%%m specifier can only be specified once in %s.\n", 326 FilenamePat); 327 return -1; 328 } 329 MergingEnabled = 1; 330 if (FilenamePat[I] == 'm') 331 lprofCurFilename.MergePoolSize = 1; 332 else { 333 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 334 I++; /* advance to 'm' */ 335 } 336 } 337 } 338 339 lprofCurFilename.NumPids = NumPids; 340 lprofCurFilename.NumHosts = NumHosts; 341 return 0; 342 } 343 344 static void parseAndSetFilename(const char *FilenamePat, 345 ProfileNameSpecifier PNS, 346 unsigned CopyFilenamePat) { 347 348 const char *OldFilenamePat = lprofCurFilename.FilenamePat; 349 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 350 351 if (PNS < OldPNS) 352 return; 353 354 if (!FilenamePat) 355 FilenamePat = DefaultProfileName; 356 357 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 358 lprofCurFilename.PNS = PNS; 359 return; 360 } 361 362 /* When PNS >= OldPNS, the last one wins. */ 363 if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 364 resetFilenameToDefault(); 365 lprofCurFilename.PNS = PNS; 366 367 if (!OldFilenamePat) { 368 if (getenv("LLVM_PROFILE_VERBOSE")) 369 PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 370 lprofCurFilename.FilenamePat, getPNSStr(PNS)); 371 } else { 372 if (getenv("LLVM_PROFILE_VERBOSE")) 373 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 374 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 375 getPNSStr(PNS)); 376 } 377 378 truncateCurrentFile(); 379 } 380 381 /* Return buffer length that is required to store the current profile 382 * filename with PID and hostname substitutions. */ 383 /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 384 #define SIGLEN 24 385 static int getCurFilenameLength() { 386 int Len; 387 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 388 return 0; 389 390 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 391 lprofCurFilename.MergePoolSize)) 392 return strlen(lprofCurFilename.FilenamePat); 393 394 Len = strlen(lprofCurFilename.FilenamePat) + 395 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 396 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 397 if (lprofCurFilename.MergePoolSize) 398 Len += SIGLEN; 399 return Len; 400 } 401 402 /* Return the pointer to the current profile file name (after substituting 403 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 404 * to store the resulting filename. If no substitution is needed, the 405 * current filename pattern string is directly returned. */ 406 static const char *getCurFilename(char *FilenameBuf) { 407 int I, J, PidLength, HostNameLength; 408 const char *FilenamePat = lprofCurFilename.FilenamePat; 409 410 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 411 return 0; 412 413 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 414 lprofCurFilename.MergePoolSize)) 415 return lprofCurFilename.FilenamePat; 416 417 PidLength = strlen(lprofCurFilename.PidChars); 418 HostNameLength = strlen(lprofCurFilename.Hostname); 419 /* Construct the new filename. */ 420 for (I = 0, J = 0; FilenamePat[I]; ++I) 421 if (FilenamePat[I] == '%') { 422 if (FilenamePat[++I] == 'p') { 423 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 424 J += PidLength; 425 } else if (FilenamePat[I] == 'h') { 426 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 427 J += HostNameLength; 428 } else if (containsMergeSpecifier(FilenamePat, I)) { 429 char LoadModuleSignature[SIGLEN]; 430 int S; 431 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 432 S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 433 lprofGetLoadModuleSignature(), ProfilePoolId); 434 if (S == -1 || S > SIGLEN) 435 S = SIGLEN; 436 memcpy(FilenameBuf + J, LoadModuleSignature, S); 437 J += S; 438 if (FilenamePat[I] != 'm') 439 I++; 440 } 441 /* Drop any unknown substitutions. */ 442 } else 443 FilenameBuf[J++] = FilenamePat[I]; 444 FilenameBuf[J] = 0; 445 446 return FilenameBuf; 447 } 448 449 /* Returns the pointer to the environment variable 450 * string. Returns null if the env var is not set. */ 451 static const char *getFilenamePatFromEnv(void) { 452 const char *Filename = getenv("LLVM_PROFILE_FILE"); 453 if (!Filename || !Filename[0]) 454 return 0; 455 return Filename; 456 } 457 458 COMPILER_RT_VISIBILITY 459 const char *__llvm_profile_get_path_prefix(void) { 460 int Length; 461 char *FilenameBuf, *Prefix; 462 const char *Filename, *PrefixEnd; 463 464 if (lprofCurFilename.ProfilePathPrefix) 465 return lprofCurFilename.ProfilePathPrefix; 466 467 Length = getCurFilenameLength(); 468 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 469 Filename = getCurFilename(FilenameBuf); 470 if (!Filename) 471 return "\0"; 472 473 PrefixEnd = lprofFindLastDirSeparator(Filename); 474 if (!PrefixEnd) 475 return "\0"; 476 477 Length = PrefixEnd - Filename + 1; 478 Prefix = (char *)malloc(Length + 1); 479 if (!Prefix) { 480 PROF_ERR("Failed to %s\n", "allocate memory."); 481 return "\0"; 482 } 483 memcpy(Prefix, Filename, Length); 484 Prefix[Length] = '\0'; 485 lprofCurFilename.ProfilePathPrefix = Prefix; 486 return Prefix; 487 } 488 489 /* This method is invoked by the runtime initialization hook 490 * InstrProfilingRuntime.o if it is linked in. Both user specified 491 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 492 * environment variable can override this default value. */ 493 COMPILER_RT_VISIBILITY 494 void __llvm_profile_initialize_file(void) { 495 const char *EnvFilenamePat; 496 const char *SelectedPat = NULL; 497 ProfileNameSpecifier PNS = PNS_unknown; 498 int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 499 500 EnvFilenamePat = getFilenamePatFromEnv(); 501 if (EnvFilenamePat) { 502 SelectedPat = EnvFilenamePat; 503 PNS = PNS_environment; 504 } else if (hasCommandLineOverrider) { 505 SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 506 PNS = PNS_command_line; 507 } else { 508 SelectedPat = NULL; 509 PNS = PNS_default; 510 } 511 512 parseAndSetFilename(SelectedPat, PNS, 0); 513 } 514 515 /* This API is directly called by the user application code. It has the 516 * highest precedence compared with LLVM_PROFILE_FILE environment variable 517 * and command line option -fprofile-instr-generate=<profile_name>. 518 */ 519 COMPILER_RT_VISIBILITY 520 void __llvm_profile_set_filename(const char *FilenamePat) { 521 parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 522 } 523 524 /* The public API for writing profile data into the file with name 525 * set by previous calls to __llvm_profile_set_filename or 526 * __llvm_profile_override_default_filename or 527 * __llvm_profile_initialize_file. */ 528 COMPILER_RT_VISIBILITY 529 int __llvm_profile_write_file(void) { 530 int rc, Length; 531 const char *Filename; 532 char *FilenameBuf; 533 int PDeathSig = 0; 534 535 if (lprofProfileDumped()) { 536 PROF_NOTE("Profile data not written to file: %s.\n", 537 "already written"); 538 return 0; 539 } 540 541 Length = getCurFilenameLength(); 542 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 543 Filename = getCurFilename(FilenameBuf); 544 545 /* Check the filename. */ 546 if (!Filename) { 547 PROF_ERR("Failed to write file : %s\n", "Filename not set"); 548 return -1; 549 } 550 551 /* Check if there is llvm/runtime version mismatch. */ 552 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 553 PROF_ERR("Runtime and instrumentation version mismatch : " 554 "expected %d, but get %d\n", 555 INSTR_PROF_RAW_VERSION, 556 (int)GET_VERSION(__llvm_profile_get_version())); 557 return -1; 558 } 559 560 // Temporarily suspend getting SIGKILL when the parent exits. 561 PDeathSig = lprofSuspendSigKill(); 562 563 /* Write profile data to the file. */ 564 rc = writeFile(Filename); 565 if (rc) 566 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 567 568 // Restore SIGKILL. 569 if (PDeathSig == 1) 570 lprofRestoreSigKill(); 571 572 return rc; 573 } 574 575 COMPILER_RT_VISIBILITY 576 int __llvm_profile_dump(void) { 577 if (!doMerging()) 578 PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 579 " of previously dumped profile data : %s. Either use %%m " 580 "in profile name or change profile name before dumping.\n", 581 "online profile merging is not on"); 582 int rc = __llvm_profile_write_file(); 583 lprofSetProfileDumped(); 584 return rc; 585 } 586 587 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 588 589 COMPILER_RT_VISIBILITY 590 int __llvm_profile_register_write_file_atexit(void) { 591 static int HasBeenRegistered = 0; 592 593 if (HasBeenRegistered) 594 return 0; 595 596 lprofSetupValueProfiler(); 597 598 HasBeenRegistered = 1; 599 return atexit(writeFileWithoutReturn); 600 } 601