-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache for translations #227
Conversation
I had designed it with the intention you could take an existing |
Yes? Start with using TranslationCache = AtomicCache<size_t, Ptr<History>>; I'm still suspicious how there won't be any ABA in this cache, but doesn't seem to violate anything in the unit-tests (which are not that big, TBH). We are not editing one memory location, but a whole lot of it. Instructions (which enable lock-free atomics) operate at 1 mem-loc at a time, does it not? If it were this simple, why cant I find this everywhere online, I wonder? |
I hate unnecessary conversions. I also hate unnecessary memory allocations especially if they are Do I really need Do not understand your concern about ABA. The object pointed to is kept alive the entire time it's in custody of a |
I ran into Even without I'm not sure where I'm headed, but here's some documentation. Looks like we have conversion, and ProcessedRequestSentence / storage is staying. https://en.cppreference.com/w/cpp/atomic/atomic#Primary_template
https://en.cppreference.com/w/cpp/types/is_trivially_copyable:
|
What was the problem with the version I wrote using an array of |
I barely tried to get that one to compile (assuming you wrote in a GitHub comment to provide a rough idea, not after testing), which is
|
There are two ways to make a store's interface.
But I think the issue is that the key is not a function of |
Nothing about this looks pleasant even after multiple re-reads. I genuinely want to know when this works for a solution - could you please provide a reference to better understand the motivations of such an interface? As for the previous comment, I've done the following: using Record = std::pair<Key, Value>;
Because |
@kpu The bergamot-translator library part of cache is added now. I've changed base to a development branch, and to avoid major trouble at reviewing 1000+LoC, for review to be done incrementally. There will be broken/untested intermediates. Further changes will have CLI alterations (I can probably settle for a chaotic "union" config, at the cost of more headhurt) which will get me to test-apps (which contribute to a decent LoC). I request a review happen now so I can work on top of this to generate smaller diffs.
This can be avoided by taking responsibility of mutex-buckets, and is done. |
src/translator/cache.h
Outdated
std::lock_guard<std::mutex> lock(mutexBuckets_[mutexId]); | ||
Record &candidate = records_[index]; | ||
|
||
if (!used_[index]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually care about these statistics enough to have an extra vector<bool>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no means to tell if I hit cache or not placing reasonable asserts (at test-apps) without this. Are there alternatives I can use?
The current assert is put in a sentence, get translation. Put same sentence again. assert(cache hits the second time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The used variable is gone, hit/miss statistics remain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some art to arriving at the default values for the cache in the different apps using it. It is clear that the BlockingService
should have just a single mutex, but the others?
My understanding is this is a coarse-to-fine-grained locking control knob. An upper bound could simply be the min(number of processors, workers) simultaneously accessing the shared memory thus providing enough partitions to avoid contention. At 1 bucket, there's max contention. At min(worker, cores) there's hopefully minimum contention. We did a search for this for L4 (#202 (comment)). Could do if necessary, bit cumbersome to setup. I see that this should be documented somewhere. Will try to see where best fits. |
const Record &candidate = records_[index]; | ||
if (equals_(key, candidate.first)) { | ||
value = candidate.second; | ||
stats_.hits += 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit late to this party, but shouldn't that be atomic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a mutex above making this section atomic..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait, you're right with regards to stats..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::atomic<int>
Mostly copied over from #202 (comment), with a few modifications.