@@ -318,14 +318,6 @@ struct LineLocationHash {
318
318
319
319
raw_ostream &operator <<(raw_ostream &OS, const LineLocation &Loc);
320
320
321
- static inline hash_code hashFuncName (StringRef F) {
322
- // If function name is already MD5 string, do not hash again.
323
- uint64_t Hash;
324
- if (F.getAsInteger (10 , Hash))
325
- Hash = MD5Hash (F);
326
- return Hash;
327
- }
328
-
329
321
// / Representation of a single sample record.
330
322
// /
331
323
// / A sample record is represented by a positive integer value, which
@@ -638,13 +630,9 @@ class SampleContext {
638
630
return getContextString (FullContext, false );
639
631
}
640
632
641
- hash_code getHashCode () const {
642
- if (hasContext ())
643
- return hash_value (getContextFrames ());
644
-
645
- // For non-context function name, use its MD5 as hash value, so that it is
646
- // consistent with the profile map's key.
647
- return hashFuncName (getName ());
633
+ uint64_t getHashCode () const {
634
+ return hasContext () ? hash_value (getContextFrames ())
635
+ : hash_value (getName ());
648
636
}
649
637
650
638
// / Set the name of the function and clear the current context.
@@ -722,12 +710,9 @@ class SampleContext {
722
710
uint32_t Attributes;
723
711
};
724
712
725
- static inline hash_code hash_value (const SampleContext &Context) {
726
- return Context.getHashCode ();
727
- }
728
-
729
- inline raw_ostream &operator <<(raw_ostream &OS, const SampleContext &Context) {
730
- return OS << Context.toString ();
713
+ static inline hash_code hash_value (const SampleContext &arg) {
714
+ return arg.hasContext () ? hash_value (arg.getContextFrames ())
715
+ : hash_value (arg.getName ());
731
716
}
732
717
733
718
class FunctionSamples ;
@@ -1217,9 +1202,6 @@ class FunctionSamples {
1217
1202
return !(*this == Other);
1218
1203
}
1219
1204
1220
- template <typename T>
1221
- const T &getKey () const ;
1222
-
1223
1205
private:
1224
1206
// / CFG hash value for the function.
1225
1207
uint64_t FunctionHash = 0 ;
@@ -1283,176 +1265,12 @@ class FunctionSamples {
1283
1265
const LocToLocMap *IRToProfileLocationMap = nullptr ;
1284
1266
};
1285
1267
1286
- template <>
1287
- inline const SampleContext &FunctionSamples::getKey<SampleContext>() const {
1288
- return getContext ();
1289
- }
1290
-
1291
1268
raw_ostream &operator <<(raw_ostream &OS, const FunctionSamples &FS);
1292
1269
1293
- // / This class is a wrapper to associative container MapT<KeyT, ValueT> using
1294
- // / the hash value of the original key as the new key. This greatly improves the
1295
- // / performance of insert and query operations especially when hash values of
1296
- // / keys are available a priori, and reduces memory usage if KeyT has a large
1297
- // / size.
1298
- // / When performing any action, if an existing entry with a given key is found,
1299
- // / and the interface "KeyT ValueT::getKey<KeyT>() const" to retrieve a value's
1300
- // / original key exists, this class checks if the given key actually matches
1301
- // / the existing entry's original key. If they do not match, this class behaves
1302
- // / as if the entry did not exist (for insertion, this means the new value will
1303
- // / replace the existing entry's value, as if it is newly inserted). If
1304
- // / ValueT::getKey<KeyT>() is not available, all keys with the same hash value
1305
- // / are considered equivalent (i.e. hash collision is silently ignored). Given
1306
- // / such feature this class should only be used where it does not affect
1307
- // / compilation correctness, for example, when loading a sample profile.
1308
- // / Assuming the hashing algorithm is uniform, the probability of hash collision
1309
- // / with 1,000,000 entries is
1310
- // / (2^64)!/((2^64-1000000)!*(2^64)^1000000) ~= 3*10^-8.
1311
- template <template <typename , typename , typename ...> typename MapT,
1312
- typename KeyT, typename ValueT, typename ... MapTArgs>
1313
- class HashKeyMap : public MapT <hash_code, ValueT, MapTArgs...> {
1314
- public:
1315
- using base_type = MapT<hash_code, ValueT, MapTArgs...>;
1316
- using key_type = hash_code;
1317
- using original_key_type = KeyT;
1318
- using mapped_type = ValueT;
1319
- using value_type = typename base_type::value_type;
1270
+ using SampleProfileMap =
1271
+ std::unordered_map<SampleContext, FunctionSamples, SampleContext::Hash>;
1320
1272
1321
- using iterator = typename base_type::iterator;
1322
- using const_iterator = typename base_type::const_iterator;
1323
-
1324
- private:
1325
- // If the value type has getKey(), retrieve its original key for comparison.
1326
- template <typename U = mapped_type,
1327
- typename = decltype (U().template getKey<original_key_type>())>
1328
- static bool
1329
- CheckKeyMatch (const original_key_type &Key, const mapped_type &ExistingValue,
1330
- original_key_type *ExistingKeyIfDifferent = nullptr ) {
1331
- const original_key_type &ExistingKey =
1332
- ExistingValue.template getKey <original_key_type>();
1333
- bool Result = (Key == ExistingKey);
1334
- if (!Result && ExistingKeyIfDifferent)
1335
- *ExistingKeyIfDifferent = ExistingKey;
1336
- return Result;
1337
- }
1338
-
1339
- // If getKey() does not exist, this overload is selected, which assumes all
1340
- // keys with the same hash are equivalent.
1341
- static bool CheckKeyMatch (...) { return true ; }
1342
-
1343
- public:
1344
- template <typename ... Ts>
1345
- std::pair<iterator, bool > try_emplace (const key_type &Hash,
1346
- const original_key_type &Key,
1347
- Ts &&...Args) {
1348
- assert (Hash == hash_value (Key));
1349
- auto Ret = base_type::try_emplace (Hash, std::forward<Ts>(Args)...);
1350
- if (!Ret.second ) {
1351
- original_key_type ExistingKey;
1352
- if (LLVM_UNLIKELY (!CheckKeyMatch (Key, Ret.first ->second , &ExistingKey))) {
1353
- dbgs () << " MD5 collision detected: " << Key << " and " << ExistingKey
1354
- << " has same hash value " << Hash << " \n " ;
1355
- Ret.second = true ;
1356
- Ret.first ->second = mapped_type (std::forward<Ts>(Args)...);
1357
- }
1358
- }
1359
- return Ret;
1360
- }
1361
-
1362
- template <typename ... Ts>
1363
- std::pair<iterator, bool > try_emplace (const original_key_type &Key,
1364
- Ts &&...Args) {
1365
- key_type Hash = hash_value (Key);
1366
- return try_emplace (Hash, Key, std::forward<Ts>(Args)...);
1367
- }
1368
-
1369
- template <typename ... Ts> std::pair<iterator, bool > emplace (Ts &&...Args) {
1370
- return try_emplace (std::forward<Ts>(Args)...);
1371
- }
1372
-
1373
- mapped_type &operator [](const original_key_type &Key) {
1374
- return try_emplace (Key, mapped_type ()).first ->second ;
1375
- }
1376
-
1377
- iterator find (const original_key_type &Key) {
1378
- key_type Hash = hash_value (Key);
1379
- auto It = base_type::find (Hash);
1380
- if (It != base_type::end ())
1381
- if (LLVM_LIKELY (CheckKeyMatch (Key, It->second )))
1382
- return It;
1383
- return base_type::end ();
1384
- }
1385
-
1386
- const_iterator find (const original_key_type &Key) const {
1387
- key_type Hash = hash_value (Key);
1388
- auto It = base_type::find (Hash);
1389
- if (It != base_type::end ())
1390
- if (LLVM_LIKELY (CheckKeyMatch (Key, It->second )))
1391
- return It;
1392
- return base_type::end ();
1393
- }
1394
-
1395
- size_t erase (const original_key_type &Ctx) {
1396
- auto It = find (Ctx);
1397
- if (It != base_type::end ()) {
1398
- base_type::erase (It);
1399
- return 1 ;
1400
- }
1401
- return 0 ;
1402
- }
1403
- };
1404
-
1405
- // / This class provides operator overloads to the map container using MD5 as the
1406
- // / key type, so that existing code can still work in most cases using
1407
- // / SampleContext as key.
1408
- // / Note: when populating container, make sure to assign the SampleContext to
1409
- // / the mapped value immediately because the key no longer holds it.
1410
- class SampleProfileMap
1411
- : public HashKeyMap<DenseMap, SampleContext, FunctionSamples> {
1412
- public:
1413
- // Convenience method because this is being used in many places. Set the
1414
- // FunctionSamples' context if its newly inserted.
1415
- mapped_type &Create (const SampleContext &Ctx) {
1416
- auto Ret = try_emplace (Ctx, FunctionSamples ());
1417
- if (Ret.second )
1418
- Ret.first ->second .setContext (Ctx);
1419
- return Ret.first ->second ;
1420
- }
1421
-
1422
- iterator find (const SampleContext &Ctx) {
1423
- return HashKeyMap<llvm::DenseMap, SampleContext, FunctionSamples>::find (
1424
- Ctx);
1425
- }
1426
-
1427
- const_iterator find (const SampleContext &Ctx) const {
1428
- return HashKeyMap<llvm::DenseMap, SampleContext, FunctionSamples>::find (
1429
- Ctx);
1430
- }
1431
-
1432
- // Overloaded find() to lookup a function by name. This is called by IPO
1433
- // passes with an actual function name, and it is possible that the profile
1434
- // reader converted function names in the profile to MD5 strings, so we need
1435
- // to check if either representation matches.
1436
- iterator find (StringRef Fname) {
1437
- hash_code Hash = hashFuncName (Fname);
1438
- auto It = base_type::find (Hash);
1439
- if (It != end ()) {
1440
- StringRef CtxName = It->second .getContext ().getName ();
1441
- if (LLVM_LIKELY (CtxName == Fname || CtxName == std::to_string (Hash)))
1442
- return It;
1443
- }
1444
- return end ();
1445
- }
1446
-
1447
- size_t erase (const SampleContext &Ctx) {
1448
- return HashKeyMap<llvm::DenseMap, SampleContext, FunctionSamples>::erase (
1449
- Ctx);
1450
- }
1451
-
1452
- size_t erase (const key_type &Key) { return base_type::erase (Key); }
1453
- };
1454
-
1455
- using NameFunctionSamples = std::pair<hash_code, const FunctionSamples *>;
1273
+ using NameFunctionSamples = std::pair<SampleContext, const FunctionSamples *>;
1456
1274
1457
1275
void sortFuncProfiles (const SampleProfileMap &ProfileMap,
1458
1276
std::vector<NameFunctionSamples> &SortedProfiles);
@@ -1498,6 +1316,8 @@ class SampleContextTrimmer {
1498
1316
bool MergeColdContext,
1499
1317
uint32_t ColdContextFrameLength,
1500
1318
bool TrimBaseProfileOnly);
1319
+ // Canonicalize context profile name and attributes.
1320
+ void canonicalizeContextProfiles ();
1501
1321
1502
1322
private:
1503
1323
SampleProfileMap &ProfileMap;
@@ -1543,12 +1363,12 @@ class ProfileConverter {
1543
1363
SampleProfileMap &OutputProfiles,
1544
1364
bool ProfileIsCS = false ) {
1545
1365
if (ProfileIsCS) {
1546
- for (const auto &I : InputProfiles) {
1547
- // Retain the profile name and clear the full context for each function
1548
- // profile.
1549
- FunctionSamples &FS = OutputProfiles. Create (I. second . getName ());
1550
- FS. merge (I. second );
1551
- }
1366
+ for (const auto &I : InputProfiles)
1367
+ OutputProfiles[I. second . getName ()]. merge (I. second );
1368
+ // Retain the profile name and clear the full context for each function
1369
+ // profile.
1370
+ for ( auto &I : OutputProfiles)
1371
+ I. second . setContext ( SampleContext (I. first ));
1552
1372
} else {
1553
1373
for (const auto &I : InputProfiles)
1554
1374
flattenNestedProfile (OutputProfiles, I.second );
0 commit comments