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