-
Notifications
You must be signed in to change notification settings - Fork 8
CachingPageTracer Optimization #172
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
Merged
tonyastolfi
merged 5 commits into
mathworks:main
from
vidyasilai:caching_page_tracer_optimization
Nov 6, 2024
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| //#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++ | ||
| // | ||
| // Part of the LLFS Project, under Apache License v2.0. | ||
| // See https://www.apache.org/licenses/LICENSE-2.0 for license information. | ||
| // SPDX short identifier: Apache-2.0 | ||
| // | ||
| //+++++++++++-+-+--+----- --- -- - - - - | ||
| #include <llfs/no_outgoing_refs_cache.hpp> | ||
|
|
||
| namespace llfs { | ||
|
|
||
| //==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - - | ||
| // | ||
| NoOutgoingRefsCache::NoOutgoingRefsCache(const PageIdFactory& page_ids) noexcept | ||
| : page_ids_{page_ids} | ||
| , cache_(this->page_ids_.get_physical_page_count().value()) | ||
| { | ||
| } | ||
|
|
||
| //==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - - | ||
| // | ||
| void NoOutgoingRefsCache::set_page_state(PageId page_id, | ||
| HasOutgoingRefs new_has_outgoing_refs_state) noexcept | ||
| { | ||
| BATT_CHECK_EQ(PageIdFactory::get_device_id(page_id), this->page_ids_.get_device_id()); | ||
| const u64 physical_page = this->page_ids_.get_physical_page(page_id); | ||
| const page_generation_int generation = this->page_ids_.get_generation(page_id); | ||
| BATT_CHECK_LT((usize)physical_page, this->cache_.size()); | ||
|
|
||
| u64 new_cache_entry = generation << this->kGenerationShift; | ||
|
|
||
| // Set the "valid" bit to 1. | ||
| // | ||
| new_cache_entry |= this->kValidBitMask; | ||
|
|
||
| // If new_has_outgoing_refs_state has value false, page_id has no outgoing references. | ||
| // | ||
| if (!new_has_outgoing_refs_state) { | ||
| // Set the "has no outgoing references" bit to 1. | ||
| // | ||
| new_cache_entry |= this->kHasNoOutgoingRefsBitMask; | ||
| } | ||
|
|
||
| u64 old_cache_entry = this->cache_[physical_page].exchange(new_cache_entry); | ||
|
|
||
| // Two sanity checks: | ||
| // 1) We are not going backwards in generation. | ||
| // 2) If the cache entry is set of the same generation multiple times, the same value should be | ||
| // set. | ||
| // | ||
| page_generation_int old_generation = old_cache_entry >> this->kGenerationShift; | ||
| BATT_CHECK_GE(generation, old_generation); | ||
| if (generation == old_generation) { | ||
| BATT_CHECK_EQ(new_cache_entry, old_cache_entry); | ||
| } | ||
| } | ||
|
|
||
| //==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - - | ||
| // | ||
| batt::BoolStatus NoOutgoingRefsCache::has_outgoing_refs(PageId page_id) const noexcept | ||
| { | ||
| BATT_CHECK_EQ(PageIdFactory::get_device_id(page_id), this->page_ids_.get_device_id()); | ||
| const u64 physical_page = this->page_ids_.get_physical_page(page_id); | ||
| const page_generation_int generation = this->page_ids_.get_generation(page_id); | ||
| BATT_CHECK_LT((usize)physical_page, this->cache_.size()); | ||
|
|
||
| u64 current_cache_entry = this->cache_[physical_page].load(); | ||
| page_generation_int stored_generation = current_cache_entry >> this->kGenerationShift; | ||
| u64 outgoing_refs_status = current_cache_entry & this->kOutgoingRefsStatusBitsMask; | ||
|
|
||
| // If the generation that is currently stored in the cache is not the same as the generation we | ||
| // are querying for, this cache entry is invalid. Thus, we return a "unknown" status. | ||
| // | ||
| if (stored_generation != generation) { | ||
| return batt::BoolStatus::kUnknown; | ||
| } | ||
|
|
||
| switch (outgoing_refs_status) { | ||
| case 0: | ||
| // Bit status 00, not traced yet. | ||
| // | ||
| return batt::BoolStatus::kUnknown; | ||
| case 1: | ||
| BATT_PANIC() << "The lower two outgoing refs bits in a cache entry can never be 01!"; | ||
| BATT_UNREACHABLE(); | ||
| case 2: | ||
| // Bit status 10, has outgoing refs. | ||
| // | ||
| return batt::BoolStatus::kTrue; | ||
| case 3: | ||
| // Bit status 11, no outgoing refs. | ||
| // | ||
| return batt::BoolStatus::kFalse; | ||
| default: | ||
| BATT_PANIC() << "Impossible outgoing refs bits state: " << outgoing_refs_status; | ||
| BATT_UNREACHABLE(); | ||
| } | ||
| } | ||
| } // namespace llfs | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| //#=##=##=#==#=#==#===#+==#+==========+==+=+=+=+=+=++=+++=+++++=-++++=-+++++++++++ | ||
| // | ||
| // Part of the LLFS Project, under Apache License v2.0. | ||
| // See https://www.apache.org/licenses/LICENSE-2.0 for license information. | ||
| // SPDX short identifier: Apache-2.0 | ||
| // | ||
| //+++++++++++-+-+--+----- --- -- - - - - | ||
|
|
||
| #pragma once | ||
| #ifndef LLFS_NO_OUTGOING_REFS_CACHE_HPP | ||
| #define LLFS_NO_OUTGOING_REFS_CACHE_HPP | ||
|
|
||
| #include <llfs/api_types.hpp> | ||
| #include <llfs/page_id_factory.hpp> | ||
|
|
||
| #include <batteries/bool_status.hpp> | ||
|
|
||
| #include <atomic> | ||
| #include <vector> | ||
|
|
||
| namespace llfs { | ||
|
|
||
| //=#=#==#==#===============+=+=+=+=++=++++++++++++++-++-+--+-+----+--------------- | ||
| /** \brief A cache to store information about a page's outgoing references to other pages. Can be | ||
| * used by an implementer of PageTracer as a way to organize and look up this information on the | ||
| * PageDevice level. This cache is implemented as a vector of unsigned 64-bit integers, where every | ||
| * element of the vector represents the outgoing refs "state" of a physical page in a PageDevice. | ||
| * The lowest bit in an element represents if the page has no outgoing refs. The second lowest bit | ||
| * represents the validity of the page's state to help determine if a page's outgoing refs have ever | ||
| * been traced. The remaining upper 62 bits are used to store the generation of the physical page. | ||
| * | ||
| * Example cache entry: 0000000000000000000000000000000000000000000000000000000000000110 | ||
| * The upper 62 bits represent generation, which in this case is 1. The second lowest bit is the | ||
| * validity bit, which is 1 here. This indicates that the page has been traced and therefore the | ||
| * cache entry contains valid information for the page of this generation. The lowest bit is 0, | ||
| * which indicates that the page has outgoing references to other pages. | ||
| */ | ||
| class NoOutgoingRefsCache | ||
| { | ||
| public: | ||
| explicit NoOutgoingRefsCache(const PageIdFactory& page_ids) noexcept; | ||
|
|
||
| NoOutgoingRefsCache(const NoOutgoingRefsCache&) = delete; | ||
| NoOutgoingRefsCache& operator=(const NoOutgoingRefsCache&) = delete; | ||
|
|
||
| //----- --- -- - - - - | ||
| /** \brief Sets the two outgoing refs state bits for the given `page_id` based on | ||
| * whether the page has outgoing refs or not, as indicated by `new_has_outgoing_refs_state`. This | ||
| * function also updates the generation stored in the cache for the physical page associated with | ||
| * `page_id`. | ||
| * | ||
| * @param page_id The id of the page whose outgoing refs information we are storing. | ||
| * | ||
| * @param new_has_outgoing_refs_state The status to store, indicating whether or not the page has | ||
| * outgoing refs. A value of `false` indicates that the page does not have any outgoing refs, and | ||
| * a value of `true` indicates that a page does have outgoing refs. | ||
| */ | ||
| void set_page_state(PageId page_id, HasOutgoingRefs new_has_outgoing_refs_state) noexcept; | ||
|
|
||
| //----- --- -- - - - - | ||
| /** \brief Queries for whether or not the page with id `page_id` contains outgoing references to | ||
| * other pages. | ||
| * | ||
| * \return Returns a `batt::BoolStatus` type, where `kFalse` indicates that the page has no | ||
| * outgoing refs, `kTrue` indicates that the page does have outgoing refs, and `kUnknown` | ||
| * indicates that the cache entry for the given page does not have any valid information stored in | ||
| * it currently. | ||
| */ | ||
| batt::BoolStatus has_outgoing_refs(PageId page_id) const noexcept; | ||
|
|
||
| private: | ||
| /** \brief A mask to retrieve the lowest two outgoing refs state bits. | ||
| */ | ||
| static constexpr u64 kOutgoingRefsStatusBitsMask = 0b11; | ||
|
|
||
| /** \brief A mask to access the "valid" bit of the two outgoing refs state bits. This is the | ||
| * higher of the two bits. | ||
| */ | ||
| static constexpr u64 kValidBitMask = 0b10; | ||
|
|
||
| /** \brief A mask to access the "has no outgoing references" bit of the two outgoing refs state | ||
| * bits. This is the lower of the two bits. | ||
| */ | ||
| static constexpr u64 kHasNoOutgoingRefsBitMask = 0b01; | ||
|
|
||
| /** \brief A constant representing the number of bits to shift a cache entry in order retrieve the | ||
| * generation stored. | ||
| */ | ||
| static constexpr u8 kGenerationShift = 2; | ||
|
|
||
| /** \brief A PageIdFactory object to help resolve physical page and generation values from a | ||
| * PageId object. | ||
| */ | ||
| const PageIdFactory page_ids_; | ||
|
|
||
| /** \brief The vector storing the cache entries, indexed by physical page id. | ||
| */ | ||
| std::vector<std::atomic<u64>> cache_; | ||
| }; | ||
| } // namespace llfs | ||
|
|
||
| #endif // LLFS_NO_OUTGOING_REFS_CACHE_HPP |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.