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 /* Open the profile data for merging. It opens the file in r+b mode with 176 * file locking. If the file has content which is compatible with the 177 * current process, it also reads in the profile data in the file and merge 178 * it with in-memory counters. After the profile data is merged in memory, 179 * the original profile data is truncated and gets ready for the profile 180 * dumper. With profile merging enabled, each executable as well as any of 181 * its instrumented shared libraries dump profile data into their own data file. 182 */ 183 static FILE *openFileForMerging(const char *ProfileFileName) { 184 FILE *ProfileFile; 185 int rc; 186 187 ProfileFile = lprofOpenFileEx(ProfileFileName); 188 if (!ProfileFile) 189 return NULL; 190 191 rc = doProfileMerging(ProfileFile); 192 if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || 193 fseek(ProfileFile, 0L, SEEK_SET) == -1) { 194 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 195 strerror(errno)); 196 fclose(ProfileFile); 197 return NULL; 198 } 199 fseek(ProfileFile, 0L, SEEK_SET); 200 return ProfileFile; 201 } 202 203 /* Write profile data to file \c OutputName. */ 204 static int writeFile(const char *OutputName) { 205 int RetVal; 206 FILE *OutputFile; 207 208 if (!doMerging()) 209 OutputFile = fopen(OutputName, "ab"); 210 else 211 OutputFile = openFileForMerging(OutputName); 212 213 if (!OutputFile) 214 return -1; 215 216 FreeHook = &free; 217 setupIOBuffer(); 218 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); 219 220 fclose(OutputFile); 221 return RetVal; 222 } 223 224 static void truncateCurrentFile(void) { 225 const char *Filename; 226 char *FilenameBuf; 227 FILE *File; 228 int Length; 229 230 Length = getCurFilenameLength(); 231 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 232 Filename = getCurFilename(FilenameBuf); 233 if (!Filename) 234 return; 235 236 /* Create the directory holding the file, if needed. */ 237 if (lprofFindFirstDirSeparator(Filename)) { 238 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 239 strncpy(Copy, Filename, Length + 1); 240 __llvm_profile_recursive_mkdir(Copy); 241 } 242 243 /* By pass file truncation to allow online raw profile 244 * merging. */ 245 if (lprofCurFilename.MergePoolSize) 246 return; 247 248 /* Truncate the file. Later we'll reopen and append. */ 249 File = fopen(Filename, "w"); 250 if (!File) 251 return; 252 fclose(File); 253 } 254 255 static const char *DefaultProfileName = "default.profraw"; 256 static void resetFilenameToDefault(void) { 257 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 258 free((void *)lprofCurFilename.FilenamePat); 259 } 260 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 261 lprofCurFilename.FilenamePat = DefaultProfileName; 262 lprofCurFilename.PNS = PNS_default; 263 } 264 265 static int containsMergeSpecifier(const char *FilenamePat, int I) { 266 return (FilenamePat[I] == 'm' || 267 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 268 /* If FilenamePat[I] is not '\0', the next byte is guaranteed 269 * to be in-bound as the string is null terminated. */ 270 FilenamePat[I + 1] == 'm')); 271 } 272 273 /* Parses the pattern string \p FilenamePat and stores the result to 274 * lprofcurFilename structure. */ 275 static int parseFilenamePattern(const char *FilenamePat, 276 unsigned CopyFilenamePat) { 277 int NumPids = 0, NumHosts = 0, I; 278 char *PidChars = &lprofCurFilename.PidChars[0]; 279 char *Hostname = &lprofCurFilename.Hostname[0]; 280 int MergingEnabled = 0; 281 282 /* Clean up cached prefix. */ 283 if (lprofCurFilename.ProfilePathPrefix) 284 free((void *)lprofCurFilename.ProfilePathPrefix); 285 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 286 287 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 288 free((void *)lprofCurFilename.FilenamePat); 289 } 290 291 if (!CopyFilenamePat) 292 lprofCurFilename.FilenamePat = FilenamePat; 293 else { 294 lprofCurFilename.FilenamePat = strdup(FilenamePat); 295 lprofCurFilename.OwnsFilenamePat = 1; 296 } 297 /* Check the filename for "%p", which indicates a pid-substitution. */ 298 for (I = 0; FilenamePat[I]; ++I) 299 if (FilenamePat[I] == '%') { 300 if (FilenamePat[++I] == 'p') { 301 if (!NumPids++) { 302 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { 303 PROF_WARN("Unable to get pid for filename pattern %s. Using the " 304 "default name.", 305 FilenamePat); 306 return -1; 307 } 308 } 309 } else if (FilenamePat[I] == 'h') { 310 if (!NumHosts++) 311 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 312 PROF_WARN("Unable to get hostname for filename pattern %s. Using " 313 "the default name.", 314 FilenamePat); 315 return -1; 316 } 317 } else if (containsMergeSpecifier(FilenamePat, I)) { 318 if (MergingEnabled) { 319 PROF_WARN("%%m specifier can only be specified once in %s.\n", 320 FilenamePat); 321 return -1; 322 } 323 MergingEnabled = 1; 324 if (FilenamePat[I] == 'm') 325 lprofCurFilename.MergePoolSize = 1; 326 else { 327 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 328 I++; /* advance to 'm' */ 329 } 330 } 331 } 332 333 lprofCurFilename.NumPids = NumPids; 334 lprofCurFilename.NumHosts = NumHosts; 335 return 0; 336 } 337 338 static void parseAndSetFilename(const char *FilenamePat, 339 ProfileNameSpecifier PNS, 340 unsigned CopyFilenamePat) { 341 342 const char *OldFilenamePat = lprofCurFilename.FilenamePat; 343 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 344 345 if (PNS < OldPNS) 346 return; 347 348 if (!FilenamePat) 349 FilenamePat = DefaultProfileName; 350 351 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 352 lprofCurFilename.PNS = PNS; 353 return; 354 } 355 356 /* When PNS >= OldPNS, the last one wins. */ 357 if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 358 resetFilenameToDefault(); 359 lprofCurFilename.PNS = PNS; 360 361 if (!OldFilenamePat) { 362 if (getenv("LLVM_PROFILE_VERBOSE")) 363 PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 364 lprofCurFilename.FilenamePat, getPNSStr(PNS)); 365 } else { 366 if (getenv("LLVM_PROFILE_VERBOSE")) 367 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 368 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 369 getPNSStr(PNS)); 370 } 371 372 truncateCurrentFile(); 373 } 374 375 /* Return buffer length that is required to store the current profile 376 * filename with PID and hostname substitutions. */ 377 /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 378 #define SIGLEN 24 379 static int getCurFilenameLength() { 380 int Len; 381 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 382 return 0; 383 384 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 385 lprofCurFilename.MergePoolSize)) 386 return strlen(lprofCurFilename.FilenamePat); 387 388 Len = strlen(lprofCurFilename.FilenamePat) + 389 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 390 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 391 if (lprofCurFilename.MergePoolSize) 392 Len += SIGLEN; 393 return Len; 394 } 395 396 /* Return the pointer to the current profile file name (after substituting 397 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 398 * to store the resulting filename. If no substitution is needed, the 399 * current filename pattern string is directly returned. */ 400 static const char *getCurFilename(char *FilenameBuf) { 401 int I, J, PidLength, HostNameLength; 402 const char *FilenamePat = lprofCurFilename.FilenamePat; 403 404 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 405 return 0; 406 407 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 408 lprofCurFilename.MergePoolSize)) 409 return lprofCurFilename.FilenamePat; 410 411 PidLength = strlen(lprofCurFilename.PidChars); 412 HostNameLength = strlen(lprofCurFilename.Hostname); 413 /* Construct the new filename. */ 414 for (I = 0, J = 0; FilenamePat[I]; ++I) 415 if (FilenamePat[I] == '%') { 416 if (FilenamePat[++I] == 'p') { 417 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 418 J += PidLength; 419 } else if (FilenamePat[I] == 'h') { 420 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 421 J += HostNameLength; 422 } else if (containsMergeSpecifier(FilenamePat, I)) { 423 char LoadModuleSignature[SIGLEN]; 424 int S; 425 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 426 S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 427 lprofGetLoadModuleSignature(), ProfilePoolId); 428 if (S == -1 || S > SIGLEN) 429 S = SIGLEN; 430 memcpy(FilenameBuf + J, LoadModuleSignature, S); 431 J += S; 432 if (FilenamePat[I] != 'm') 433 I++; 434 } 435 /* Drop any unknown substitutions. */ 436 } else 437 FilenameBuf[J++] = FilenamePat[I]; 438 FilenameBuf[J] = 0; 439 440 return FilenameBuf; 441 } 442 443 /* Returns the pointer to the environment variable 444 * string. Returns null if the env var is not set. */ 445 static const char *getFilenamePatFromEnv(void) { 446 const char *Filename = getenv("LLVM_PROFILE_FILE"); 447 if (!Filename || !Filename[0]) 448 return 0; 449 return Filename; 450 } 451 452 COMPILER_RT_VISIBILITY 453 const char *__llvm_profile_get_path_prefix(void) { 454 int Length; 455 char *FilenameBuf, *Prefix; 456 const char *Filename, *PrefixEnd; 457 458 if (lprofCurFilename.ProfilePathPrefix) 459 return lprofCurFilename.ProfilePathPrefix; 460 461 Length = getCurFilenameLength(); 462 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 463 Filename = getCurFilename(FilenameBuf); 464 if (!Filename) 465 return "\0"; 466 467 PrefixEnd = lprofFindLastDirSeparator(Filename); 468 if (!PrefixEnd) 469 return "\0"; 470 471 Length = PrefixEnd - Filename + 1; 472 Prefix = (char *)malloc(Length + 1); 473 if (!Prefix) { 474 PROF_ERR("Failed to %s\n", "allocate memory."); 475 return "\0"; 476 } 477 memcpy(Prefix, Filename, Length); 478 Prefix[Length] = '\0'; 479 lprofCurFilename.ProfilePathPrefix = Prefix; 480 return Prefix; 481 } 482 483 /* This method is invoked by the runtime initialization hook 484 * InstrProfilingRuntime.o if it is linked in. Both user specified 485 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 486 * environment variable can override this default value. */ 487 COMPILER_RT_VISIBILITY 488 void __llvm_profile_initialize_file(void) { 489 const char *EnvFilenamePat; 490 const char *SelectedPat = NULL; 491 ProfileNameSpecifier PNS = PNS_unknown; 492 int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 493 494 EnvFilenamePat = getFilenamePatFromEnv(); 495 if (EnvFilenamePat) { 496 SelectedPat = EnvFilenamePat; 497 PNS = PNS_environment; 498 } else if (hasCommandLineOverrider) { 499 SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 500 PNS = PNS_command_line; 501 } else { 502 SelectedPat = NULL; 503 PNS = PNS_default; 504 } 505 506 parseAndSetFilename(SelectedPat, PNS, 0); 507 } 508 509 /* This API is directly called by the user application code. It has the 510 * highest precedence compared with LLVM_PROFILE_FILE environment variable 511 * and command line option -fprofile-instr-generate=<profile_name>. 512 */ 513 COMPILER_RT_VISIBILITY 514 void __llvm_profile_set_filename(const char *FilenamePat) { 515 parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 516 } 517 518 /* The public API for writing profile data into the file with name 519 * set by previous calls to __llvm_profile_set_filename or 520 * __llvm_profile_override_default_filename or 521 * __llvm_profile_initialize_file. */ 522 COMPILER_RT_VISIBILITY 523 int __llvm_profile_write_file(void) { 524 int rc, Length; 525 const char *Filename; 526 char *FilenameBuf; 527 528 if (lprofProfileDumped()) { 529 PROF_NOTE("Profile data not written to file: %s.\n", 530 "already written"); 531 return 0; 532 } 533 534 Length = getCurFilenameLength(); 535 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 536 Filename = getCurFilename(FilenameBuf); 537 538 /* Check the filename. */ 539 if (!Filename) { 540 PROF_ERR("Failed to write file : %s\n", "Filename not set"); 541 return -1; 542 } 543 544 /* Check if there is llvm/runtime version mismatch. */ 545 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 546 PROF_ERR("Runtime and instrumentation version mismatch : " 547 "expected %d, but get %d\n", 548 INSTR_PROF_RAW_VERSION, 549 (int)GET_VERSION(__llvm_profile_get_version())); 550 return -1; 551 } 552 553 /* Write profile data to the file. */ 554 rc = writeFile(Filename); 555 if (rc) 556 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 557 return rc; 558 } 559 560 COMPILER_RT_VISIBILITY 561 int __llvm_profile_dump(void) { 562 if (!doMerging()) 563 PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 564 " of previously dumped profile data : %s. Either use %%m " 565 "in profile name or change profile name before dumping.\n", 566 "online profile merging is not on"); 567 int rc = __llvm_profile_write_file(); 568 lprofSetProfileDumped(); 569 return rc; 570 } 571 572 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 573 574 COMPILER_RT_VISIBILITY 575 int __llvm_profile_register_write_file_atexit(void) { 576 static int HasBeenRegistered = 0; 577 578 if (HasBeenRegistered) 579 return 0; 580 581 lprofSetupValueProfiler(); 582 583 HasBeenRegistered = 1; 584 return atexit(writeFileWithoutReturn); 585 } 586