diff options
author | Kellen Renshaw <kellen.renshaw@canonical.com> | 2021-10-27 22:32:20 +0000 |
---|---|---|
committer | Kellen Renshaw <kellen.renshaw@canonical.com> | 2022-01-07 20:39:08 +0000 |
commit | d9aa77225d5813dd1dd9adec16b22064d7b999aa (patch) | |
tree | fec6dc6ad09727b5a8efdd88b6b3dc708160e1c0 | |
parent | 819ecf7b8160e4eac6131e710871397233f8a8b6 (diff) | |
download | ceph-d9aa77225d5813dd1dd9adec16b22064d7b999aa.tar.gz |
test/allocator_replay_test: Add replay_alloc option
New replay_alloc option added to ceph_test_alloc_replay binary
that permits the loading of a dump produced by
"ceph daemon osd.<id> bluestore allocator dump block" and replaying
a list of allocation requests against the loaded allocator state an
arbitrary number of times (default, 100).
Once the allocator dump is loaded, the fragmentation state and
free space information are printed. Then the list of allocation
requests is replayed against that state.
Output consists of the time in ns that the allocator took to return
the requested allocation, along with the request.
If an allocation request fails or the list of allocation requests is
completed, the error info, if any, and the fragementation and
free space information is printed.
The list of allocations is formatted as a file with one allocation
request per line, with space separated values for "want", "unit",
"max", and "hint". Values can be any integer format supported by
std::scanf()'s %u formatter.
The allocation request line format:
<want> <unit> [max] [hint]
Example request lines:
0x4000 0x4000 0x4000 0x0
0x18000 0x4000 0x18000 0x0
The "want" and "unit" values are required.
Optional request values are 0 if not present in the request.
Fixes: https://tracker.ceph.com/issues/53571
Signed-off-by: Kellen Renshaw <kellen.renshaw@canonical.com>
-rw-r--r-- | src/test/objectstore/allocator_replay_test.cc | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/src/test/objectstore/allocator_replay_test.cc b/src/test/objectstore/allocator_replay_test.cc index 811cc92cdea..401eaa42703 100644 --- a/src/test/objectstore/allocator_replay_test.cc +++ b/src/test/objectstore/allocator_replay_test.cc @@ -18,8 +18,14 @@ using namespace std; void usage(const string &name) { - cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit>" - << std::endl; + cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit|replay_alloc alloc_list_file>" << std::endl; +} + +void usage_replay_alloc(const string &name) { + cerr << "Detailed replay_alloc usage: " << name << " <allocator_dump_JSON> replay_alloc <alloc_list_file> [number of replays]" << std::endl; + cerr << "The number of replays defaults to 1." << std::endl; + cerr << "The \"alloc_list_file\" parameter should be a file with allocation requests, one per line." << std::endl; + cerr << "Allocation request format (space separated, optional parameters are 0 if not given): want unit [max] [hint]" << std::endl; } int replay_and_check_for_duplicate(char* fname) @@ -389,5 +395,99 @@ int main(int argc, char **argv) << ", unit:" << alloc_unit << std::endl; return 0; }); + } else if (strcmp(argv[2], "replay_alloc") == 0) { + if (argc < 4) { + std::cerr << "Error: insufficient arguments for \"replay_alloc\" option." + << std::endl; + usage_replay_alloc(argv[0]); + return 1; + } + return replay_free_dump_and_apply(argv[1], + [&](Allocator *a, const string &aname) { + ceph_assert(a); + std::cout << "Fragmentation:" << a->get_fragmentation() + << std::endl; + std::cout << "Fragmentation score:" << a->get_fragmentation_score() + << std::endl; + std::cout << "Free:" << std::hex << a->get_free() << std::dec + << std::endl; + { + /* replay a set of allocation requests */ + char s[4096]; + + FILE *f_alloc_list = fopen(argv[3], "r"); + if (!f_alloc_list) { + std::cerr << "error: unable to open " << argv[3] << std::endl; + return -1; + } + + /* Replay user specified number of times to simulate extended activity + * Defaults to 1 replay. + */ + auto replay_count = 1; + if (argc == 5) { + replay_count = atoi(argv[4]); + } + + for (auto i = 0; i < replay_count; ++i) { + while (fgets(s, sizeof(s), f_alloc_list) != nullptr) { + /* parse allocation request */ + uint64_t want = 0, unit = 0, max = 0, hint = 0; + + if (std::sscanf(s, "%ji %ji %ji %ji", &want, &unit, &max, &hint) < 2) + { + cerr << "Error: malformed allocation request:" << std::endl; + cerr << s << std::endl; + /* do not attempt to allocate a malformed request */ + continue; + } + + /* timestamp for allocation start */ + auto t0 = ceph::mono_clock::now(); + + /* allocate */ + PExtentVector extents; + auto r = a->allocate(want, unit, max, hint, &extents); + if (r < 0) { + /* blind replays of allocations may run out of space, provide info for easy confirmation */ + std::cerr << "Error: allocation failure code: " << r + << " requested want/unit/max/hint (hex): " << std::hex + << want << "/" << unit << "/" << max << "/" << hint + << std::dec << std::endl; + std::cerr << "Fragmentation:" << a->get_fragmentation() + << std::endl; + std::cerr << "Fragmentation score:" << a->get_fragmentation_score() + << std::endl; + std::cerr << "Free:" << std::hex << a->get_free() << std::dec + << std::endl; + /* return 0 if the allocator ran out of space */ + if (r == -ENOSPC) { + return 0; + } + return -1; + } + + /* Outputs the allocation's duration in nanoseconds and the allocation request parameters */ + std::cout << "Duration (ns): " << (ceph::mono_clock::now() - t0).count() + << " want/unit/max/hint (hex): " << std::hex + << want << "/" << unit << "/" << max << "/" << hint + << std::dec << std::endl; + + /* Do not release. */ + //alloc->release(extents); + extents.clear(); + } + fseek(f_alloc_list, 0, SEEK_SET); + } + fclose(f_alloc_list); + std::cout << "Fragmentation:" << a->get_fragmentation() + << std::endl; + std::cout << "Fragmentation score:" << a->get_fragmentation_score() + << std::endl; + std::cout << "Free:" << std::hex << a->get_free() << std::dec + << std::endl; + } + return 0; + }); } } |