Skip to content

Commit 3c9a3c8

Browse files
Jiayue Baofacebook-github-bot
authored andcommitted
Add thread memory tracker util class to compute object size
Summary: Add a util class `ThreadMemoryTracker` to help compute object size when enabling size-awareness. The basic idea is - Use Jemalloc util function(`thread.allocatedp` and `thread.deallocatedp`) to calculate allocated memory and deallocated memory in the current thread: ``` memory usage = allocate memory - deallocated memory ``` - Get the currently used memory before and after the object construction, the difference is the object memory: ``` get before memory usage ...construct object get after memory usage object size = after memory usage - before memory usage ``` Example: ``` // initialize memory tracker only at the beginning ThreadMemoryTracke tMemTracker; ... auto beforeMemUsage = tMemTracker.getMemUsageBytes(); ...construct the object auto afterMemUsage = tMemTracker.getMemUsageBytes(); auto objectSize = LIKELY(afterMemUsage > beforeMemUsage) ? (afterMemUsage - beforeMemUsage) : 0; ``` Reviewed By: therealgymmy Differential Revision: D40958506 fbshipit-source-id: 967c214ab7b96b9787f20ba55c6eb6c0771a90b1
1 parent 584848d commit 3c9a3c8

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <folly/logging/xlog.h>
20+
#include <folly/memory/Malloc.h>
21+
22+
namespace facebook {
23+
namespace cachelib {
24+
namespace objcache2 {
25+
26+
// Tracks the memory usage in a local thread.
27+
// Use this class to calculate the object size when enabling size-awareness.
28+
// Example:
29+
// ThreadMemoryTracker tMemTracker;
30+
// auto beforeMemUsage = tMemTracker.getMemUsageBytes();
31+
// ... create the object
32+
// auto afterMemUsage = tMemTracker.getMemUsageBytes();
33+
// ...
34+
// auto objectSize = LIKELY(afterMemUsage > beforeMemUsage) ?
35+
// (afterMemUsage - beforeMemUsage) : 0;
36+
class ThreadMemoryTracker {
37+
public:
38+
ThreadMemoryTracker() {
39+
if (folly::usingJEMalloc()) {
40+
size_t size = sizeof(uint64_t*);
41+
mallctl("thread.allocatedp", &allocPtr_, &size, nullptr, 0);
42+
mallctl("thread.deallocatedp", &deallocPtr_, &size, nullptr, 0);
43+
}
44+
}
45+
46+
size_t getMemUsageBytes() {
47+
if (!allocPtr_ || !deallocPtr_) {
48+
return 0;
49+
}
50+
if (*allocPtr_ < *deallocPtr_) {
51+
return 0;
52+
}
53+
return *allocPtr_ - *deallocPtr_;
54+
}
55+
56+
private:
57+
// pointer of the total number of bytes ever allocated by the calling thread
58+
uint64_t* allocPtr_{nullptr};
59+
// pointer of the total number of bytes ever deallocated by the calling thread
60+
uint64_t* deallocPtr_{nullptr};
61+
};
62+
} // namespace objcache2
63+
} // namespace cachelib
64+
} // namespace facebook
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <folly/Benchmark.h>
18+
#include <gtest/gtest.h>
19+
20+
#include "cachelib/experimental/objcache2/util/ThreadMemoryTracker.h"
21+
22+
namespace facebook {
23+
namespace cachelib {
24+
namespace objcache2 {
25+
namespace test {
26+
using Object = std::array<char, 16>;
27+
28+
static const size_t expected =
29+
folly::usingJEMalloc() ? folly::goodMallocSize(sizeof(Object)) : 0;
30+
31+
TEST(ThreadMemoryTrackerTest, Basic) {
32+
ThreadMemoryTracker tMemTracker;
33+
auto beforeMemUsage = tMemTracker.getMemUsageBytes();
34+
auto ptr = std::make_unique<Object>();
35+
folly::doNotOptimizeAway(ptr);
36+
auto afterMemUsage = tMemTracker.getMemUsageBytes();
37+
auto objectSize = LIKELY(afterMemUsage > beforeMemUsage)
38+
? (afterMemUsage - beforeMemUsage)
39+
: 0;
40+
EXPECT_EQ(objectSize, expected);
41+
}
42+
43+
TEST(ThreadMemoryTrackerTest, Iteration) {
44+
ThreadMemoryTracker tMemTracker;
45+
for (auto i = 0; i < 100; i++) {
46+
auto beforeMemUsage = tMemTracker.getMemUsageBytes();
47+
auto ptr = std::make_unique<Object>();
48+
folly::doNotOptimizeAway(ptr);
49+
auto afterMemUsage = tMemTracker.getMemUsageBytes();
50+
auto objectSize = LIKELY(afterMemUsage > beforeMemUsage)
51+
? (afterMemUsage - beforeMemUsage)
52+
: 0;
53+
EXPECT_EQ(objectSize, expected);
54+
}
55+
}
56+
57+
} // namespace test
58+
} // namespace objcache2
59+
} // namespace cachelib
60+
} // namespace facebook

0 commit comments

Comments
 (0)