forked from pytorch/FBGEMM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CodeCache.h
135 lines (117 loc) · 3.5 KB
/
CodeCache.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <condition_variable>
#include <future>
#include <map>
#if __cplusplus >= 201402L && !defined(__APPLE__)
// For C++14, use shared_timed_mutex.
// some macOS C++14 compilers don't support shared_timed_mutex.
#define FBGEMM_USE_SHARED_TIMED_MUTEX
#endif
#ifdef FBGEMM_USE_SHARED_TIMED_MUTEX
#include <shared_mutex>
#else
#include <mutex>
#endif
#ifdef FBCODE_CAFFE2
#include <folly/container/F14Map.h>
#endif
namespace fbgemm {
/**
* @brief Thread safe cache for microkernels, ensures single creation per key.
* @tparam KEY Type of unique key (typically a tuple)
* @tparam VALUE Type of the microkernel function (Typically a function pointer)
* @tparam THREAD_LOCAL use thread local and avoid locking (default false)
*/
template <typename KEY, typename VALUE, bool THREAD_LOCAL = false>
class CodeCache {
private:
#ifdef FBCODE_CAFFE2
folly::F14FastMap<KEY, std::shared_future<VALUE>> values_;
#else
std::map<KEY, std::shared_future<VALUE>> values_;
#endif
#ifdef FBGEMM_USE_SHARED_TIMED_MUTEX
std::shared_timed_mutex mutex_;
#else
std::mutex mutex_;
#endif
public:
CodeCache(const CodeCache&) = delete;
CodeCache& operator=(const CodeCache&) = delete;
CodeCache() {}
template <typename GENFUNC>
VALUE getOrCreate(const KEY& key, GENFUNC generatorFunction) {
#ifdef FBGEMM_USE_SHARED_TIMED_MUTEX
std::shared_lock<std::shared_timed_mutex> sharedLock(mutex_);
#else
std::unique_lock<std::mutex> uniqueLock(mutex_);
#endif
// Check for existence of the key
auto it = values_.find(key);
if (it != values_.end()) {
return it->second.get();
} else {
#ifdef FBGEMM_USE_SHARED_TIMED_MUTEX
sharedLock.unlock();
std::unique_lock<std::shared_timed_mutex> uniqueLock(mutex_);
// Need to look up again because there could be race condition from
// the time gap between sharedLock.unlock() and creating uniqueLock.
it = values_.find(key);
if (it == values_.end()) {
#endif
std::promise<VALUE> returnPromise;
values_[key] = returnPromise.get_future().share();
uniqueLock.unlock();
// The value (code) generation is not happening under a lock
VALUE val = generatorFunction();
returnPromise.set_value(val);
return val;
#ifdef FBGEMM_USE_SHARED_TIMED_MUTEX
} else {
return it->second.get();
}
#endif
}
}
};
// This class must be used as a static variable.
template <typename KEY, typename VALUE>
class CodeCache<KEY, VALUE, /*THREAD_LOCAL=*/true> {
private:
#ifdef FBCODE_CAFFE2
static folly::F14FastMap<KEY, VALUE>& getValues_() {
static thread_local folly::F14FastMap<KEY, VALUE>
values_; /* library-local */
return values_;
}
#else
static std::map<KEY, VALUE>& getValues_() {
static thread_local std::map<KEY, VALUE> values_;
return values_;
}
#endif
public:
CodeCache(const CodeCache&) = delete;
CodeCache& operator=(const CodeCache&) = delete;
CodeCache() {}
template <typename GENFUNC>
VALUE getOrCreate(const KEY& key, GENFUNC generatorFunction) {
// Check for existence of the key
auto it = getValues_().find(key);
if (it != getValues_().end()) {
return it->second;
} else {
VALUE val = generatorFunction();
getValues_()[key] = val;
return val;
}
}
};
} // namespace fbgemm