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 const char *ProfilePathPrefix; 67 char PidChars[MAX_PID_SIZE]; 68 char Hostname[COMPILER_RT_MAX_HOSTLEN]; 69 unsigned NumPids; 70 unsigned NumHosts; 71 /* When in-process merging is enabled, this parameter specifies 72 * the total number of profile data files shared by all the processes 73 * spawned from the same binary. By default the value is 1. If merging 74 * is not enabled, its value should be 0. This parameter is specified 75 * by the %[0-9]m specifier. For instance %2m enables merging using 76 * 2 profile data files. %1m is equivalent to %m. Also %m specifier 77 * can only appear once at the end of the name pattern. */ 78 unsigned MergePoolSize; 79 ProfileNameSpecifier PNS; 80 } lprofFilename; 81 82 lprofFilename lprofCurFilename = {0, 0, {0}, {0}, 0, 0, 0, PNS_unknown}; 83 84 int getpid(void); 85 static int getCurFilenameLength(); 86 static const char *getCurFilename(char *FilenameBuf); 87 static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } 88 89 /* Return 1 if there is an error, otherwise return 0. */ 90 static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, 91 void **WriterCtx) { 92 uint32_t I; 93 FILE *File = (FILE *)*WriterCtx; 94 for (I = 0; I < NumIOVecs; I++) { 95 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 96 IOVecs[I].NumElm) 97 return 1; 98 } 99 return 0; 100 } 101 102 COMPILER_RT_VISIBILITY ProfBufferIO * 103 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 104 FreeHook = &free; 105 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 106 VPBufferSize = BufferSz; 107 return lprofCreateBufferIO(fileWriter, File); 108 } 109 110 static void setupIOBuffer() { 111 const char *BufferSzStr = 0; 112 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 113 if (BufferSzStr && BufferSzStr[0]) { 114 VPBufferSize = atoi(BufferSzStr); 115 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 116 } 117 } 118 119 /* Read profile data in \c ProfileFile and merge with in-memory 120 profile counters. Returns -1 if there is fatal error, otheriwse 121 0 is returned. 122 */ 123 static int doProfileMerging(FILE *ProfileFile) { 124 uint64_t ProfileFileSize; 125 char *ProfileBuffer; 126 127 if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 128 PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 129 strerror(errno)); 130 return -1; 131 } 132 ProfileFileSize = ftell(ProfileFile); 133 134 /* Restore file offset. */ 135 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 136 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 137 strerror(errno)); 138 return -1; 139 } 140 141 /* Nothing to merge. */ 142 if (ProfileFileSize < sizeof(__llvm_profile_header)) { 143 if (ProfileFileSize) 144 PROF_WARN("Unable to merge profile data: %s\n", 145 "source profile file is too small."); 146 return 0; 147 } 148 149 ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 150 fileno(ProfileFile), 0); 151 if (ProfileBuffer == MAP_FAILED) { 152 PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 153 strerror(errno)); 154 return -1; 155 } 156 157 if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 158 (void)munmap(ProfileBuffer, ProfileFileSize); 159 PROF_WARN("Unable to merge profile data: %s\n", 160 "source profile file is not compatible."); 161 return 0; 162 } 163 164 /* Now start merging */ 165 __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 166 (void)munmap(ProfileBuffer, ProfileFileSize); 167 168 return 0; 169 } 170 171 /* Open the profile data for merging. It opens the file in r+b mode with 172 * file locking. If the file has content which is compatible with the 173 * current process, it also reads in the profile data in the file and merge 174 * it with in-memory counters. After the profile data is merged in memory, 175 * the original profile data is truncated and gets ready for the profile 176 * dumper. With profile merging enabled, each executable as well as any of 177 * its instrumented shared libraries dump profile data into their own data file. 178 */ 179 static FILE *openFileForMerging(const char *ProfileFileName) { 180 FILE *ProfileFile; 181 int rc; 182 183 ProfileFile = lprofOpenFileEx(ProfileFileName); 184 if (!ProfileFile) 185 return NULL; 186 187 rc = doProfileMerging(ProfileFile); 188 if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || 189 fseek(ProfileFile, 0L, SEEK_SET) == -1) { 190 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 191 strerror(errno)); 192 fclose(ProfileFile); 193 return NULL; 194 } 195 fseek(ProfileFile, 0L, SEEK_SET); 196 return ProfileFile; 197 } 198 199 /* Write profile data to file \c OutputName. */ 200 static int writeFile(const char *OutputName) { 201 int RetVal; 202 FILE *OutputFile; 203 204 if (!doMerging()) 205 OutputFile = fopen(OutputName, "ab"); 206 else 207 OutputFile = openFileForMerging(OutputName); 208 209 if (!OutputFile) 210 return -1; 211 212 FreeHook = &free; 213 setupIOBuffer(); 214 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); 215 216 fclose(OutputFile); 217 return RetVal; 218 } 219 220 static void truncateCurrentFile(void) { 221 const char *Filename; 222 char *FilenameBuf; 223 FILE *File; 224 int Length; 225 226 Length = getCurFilenameLength(); 227 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 228 Filename = getCurFilename(FilenameBuf); 229 if (!Filename) 230 return; 231 232 /* Create the directory holding the file, if needed. */ 233 if (lprofFindFirstDirSeparator(Filename)) { 234 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 235 strncpy(Copy, Filename, Length + 1); 236 __llvm_profile_recursive_mkdir(Copy); 237 } 238 239 /* By pass file truncation to allow online raw profile 240 * merging. */ 241 if (lprofCurFilename.MergePoolSize) 242 return; 243 244 /* Truncate the file. Later we'll reopen and append. */ 245 File = fopen(Filename, "w"); 246 if (!File) 247 return; 248 fclose(File); 249 } 250 251 static const char *DefaultProfileName = "default.profraw"; 252 static void resetFilenameToDefault(void) { 253 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 254 lprofCurFilename.FilenamePat = DefaultProfileName; 255 lprofCurFilename.PNS = PNS_default; 256 } 257 258 static int containsMergeSpecifier(const char *FilenamePat, int I) { 259 return (FilenamePat[I] == 'm' || 260 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 261 /* If FilenamePat[I] is not '\0', the next byte is guaranteed 262 * to be in-bound as the string is null terminated. */ 263 FilenamePat[I + 1] == 'm')); 264 } 265 266 /* Parses the pattern string \p FilenamePat and stores the result to 267 * lprofcurFilename structure. */ 268 static int parseFilenamePattern(const char *FilenamePat) { 269 int NumPids = 0, NumHosts = 0, I; 270 char *PidChars = &lprofCurFilename.PidChars[0]; 271 char *Hostname = &lprofCurFilename.Hostname[0]; 272 int MergingEnabled = 0; 273 274 /* Clean up cached prefix. */ 275 if (lprofCurFilename.ProfilePathPrefix) 276 free((void *)lprofCurFilename.ProfilePathPrefix); 277 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 278 279 lprofCurFilename.FilenamePat = FilenamePat; 280 /* Check the filename for "%p", which indicates a pid-substitution. */ 281 for (I = 0; FilenamePat[I]; ++I) 282 if (FilenamePat[I] == '%') { 283 if (FilenamePat[++I] == 'p') { 284 if (!NumPids++) { 285 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { 286 PROF_WARN( 287 "Unable to parse filename pattern %s. Using the default name.", 288 FilenamePat); 289 return -1; 290 } 291 } 292 } else if (FilenamePat[I] == 'h') { 293 if (!NumHosts++) 294 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 295 PROF_WARN( 296 "Unable to parse filename pattern %s. Using the default name.", 297 FilenamePat); 298 return -1; 299 } 300 } else if (containsMergeSpecifier(FilenamePat, I)) { 301 if (MergingEnabled) { 302 PROF_WARN("%%m specifier can only be specified once in %s.\n", 303 FilenamePat); 304 return -1; 305 } 306 MergingEnabled = 1; 307 if (FilenamePat[I] == 'm') 308 lprofCurFilename.MergePoolSize = 1; 309 else { 310 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 311 I++; /* advance to 'm' */ 312 } 313 } 314 } 315 316 lprofCurFilename.NumPids = NumPids; 317 lprofCurFilename.NumHosts = NumHosts; 318 return 0; 319 } 320 321 static void parseAndSetFilename(const char *FilenamePat, 322 ProfileNameSpecifier PNS) { 323 324 const char *OldFilenamePat = lprofCurFilename.FilenamePat; 325 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 326 327 if (PNS < OldPNS) 328 return; 329 330 if (!FilenamePat) 331 FilenamePat = DefaultProfileName; 332 333 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 334 lprofCurFilename.PNS = PNS; 335 return; 336 } 337 338 /* When PNS >= OldPNS, the last one wins. */ 339 if (!FilenamePat || parseFilenamePattern(FilenamePat)) 340 resetFilenameToDefault(); 341 lprofCurFilename.PNS = PNS; 342 343 if (!OldFilenamePat) { 344 PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 345 lprofCurFilename.FilenamePat, getPNSStr(PNS)); 346 } else { 347 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 348 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 349 getPNSStr(PNS)); 350 } 351 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 COMPILER_RT_VISIBILITY 433 const char *__llvm_profile_get_path_prefix(void) { 434 int Length; 435 char *FilenameBuf, *Prefix; 436 const char *Filename, *PrefixEnd; 437 438 if (lprofCurFilename.ProfilePathPrefix) 439 return lprofCurFilename.ProfilePathPrefix; 440 441 Length = getCurFilenameLength(); 442 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 443 Filename = getCurFilename(FilenameBuf); 444 if (!Filename) 445 return "\0"; 446 447 PrefixEnd = lprofFindLastDirSeparator(Filename); 448 if (!PrefixEnd) 449 return "\0"; 450 451 Length = PrefixEnd - Filename + 1; 452 Prefix = (char *)malloc(Length + 1); 453 if (!Prefix) { 454 PROF_ERR("Failed to %s\n", "allocate memory."); 455 return "\0"; 456 } 457 memcpy(Prefix, Filename, Length); 458 Prefix[Length] = '\0'; 459 lprofCurFilename.ProfilePathPrefix = Prefix; 460 return Prefix; 461 } 462 463 /* This method is invoked by the runtime initialization hook 464 * InstrProfilingRuntime.o if it is linked in. Both user specified 465 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 466 * environment variable can override this default value. */ 467 COMPILER_RT_VISIBILITY 468 void __llvm_profile_initialize_file(void) { 469 const char *EnvFilenamePat; 470 const char *SelectedPat = NULL; 471 ProfileNameSpecifier PNS = PNS_unknown; 472 int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 473 474 EnvFilenamePat = getFilenamePatFromEnv(); 475 if (EnvFilenamePat) { 476 SelectedPat = EnvFilenamePat; 477 PNS = PNS_environment; 478 } else if (hasCommandLineOverrider) { 479 SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 480 PNS = PNS_command_line; 481 } else { 482 SelectedPat = NULL; 483 PNS = PNS_default; 484 } 485 486 parseAndSetFilename(SelectedPat, PNS); 487 } 488 489 /* This API is directly called by the user application code. It has the 490 * highest precedence compared with LLVM_PROFILE_FILE environment variable 491 * and command line option -fprofile-instr-generate=<profile_name>. 492 */ 493 COMPILER_RT_VISIBILITY 494 void __llvm_profile_set_filename(const char *FilenamePat) { 495 parseAndSetFilename(FilenamePat, PNS_runtime_api); 496 } 497 498 /* The public API for writing profile data into the file with name 499 * set by previous calls to __llvm_profile_set_filename or 500 * __llvm_profile_override_default_filename or 501 * __llvm_profile_initialize_file. */ 502 COMPILER_RT_VISIBILITY 503 int __llvm_profile_write_file(void) { 504 int rc, Length; 505 const char *Filename; 506 char *FilenameBuf; 507 508 Length = getCurFilenameLength(); 509 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 510 Filename = getCurFilename(FilenameBuf); 511 512 /* Check the filename. */ 513 if (!Filename) { 514 PROF_ERR("Failed to write file : %s\n", "Filename not set"); 515 return -1; 516 } 517 518 /* Check if there is llvm/runtime version mismatch. */ 519 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 520 PROF_ERR("Runtime and instrumentation version mismatch : " 521 "expected %d, but get %d\n", 522 INSTR_PROF_RAW_VERSION, 523 (int)GET_VERSION(__llvm_profile_get_version())); 524 return -1; 525 } 526 527 /* Write profile data to the file. */ 528 rc = writeFile(Filename); 529 if (rc) 530 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 531 return rc; 532 } 533 534 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 535 536 COMPILER_RT_VISIBILITY 537 int __llvm_profile_register_write_file_atexit(void) { 538 static int HasBeenRegistered = 0; 539 540 if (HasBeenRegistered) 541 return 0; 542 543 lprofSetupValueProfiler(); 544 545 HasBeenRegistered = 1; 546 return atexit(writeFileWithoutReturn); 547 } 548