llvm.org GIT mirror llvm / 2995c25
Support: Add a cache pruning policy parser. The idea is that the policy string fully specifies the policy and is portable between clients. Differential Revision: https://reviews.llvm.org/D31020 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297927 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 3 years ago
5 changed file(s) with 154 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
141141 struct CachingOptions {
142142 std::string Path; // Path to the cache, empty to disable.
143143 CachePruningPolicy Policy;
144
145 CachingOptions() {
146 Policy.Interval = std::chrono::seconds(1200);
147 Policy.Expiration = std::chrono::hours(7 * 24); // 1w
148 Policy.PercentageOfAvailableSpace = 75;
149 };
150144 };
151145
152146 /// Provide a path to a directory where to store the cached files for
1919
2020 namespace llvm {
2121
22 template class Expected;
23
24 /// Policy for the pruneCache() function. A default constructed
25 /// CachePruningPolicy provides a reasonable default policy.
2226 struct CachePruningPolicy {
2327 /// The pruning interval. This is intended to be used to avoid scanning the
2428 /// directory too often. It does not impact the decision of which file to
2529 /// prune. A value of 0 forces the scan to occur.
26 std::chrono::seconds Interval = std::chrono::seconds::zero();
30 std::chrono::seconds Interval = std::chrono::seconds(1200);
2731
2832 /// The expiration for a file. When a file hasn't been accessed for Expiration
2933 /// seconds, it is removed from the cache. A value of 0 disables the
3034 /// expiration-based pruning.
31 std::chrono::seconds Expiration = std::chrono::seconds::zero();
35 std::chrono::seconds Expiration = std::chrono::hours(7 * 24); // 1w
3236
3337 /// The maximum size for the cache directory, in terms of percentage of the
3438 /// available space on the the disk. Set to 100 to indicate no limit, 50 to
3539 /// indicate that the cache size will not be left over half the available disk
3640 /// space. A value over 100 will be reduced to 100. A value of 0 disables the
3741 /// size-based pruning.
38 unsigned PercentageOfAvailableSpace = 0;
42 unsigned PercentageOfAvailableSpace = 75;
3943 };
44
45 /// Parse the given string as a cache pruning policy. Defaults are taken from a
46 /// default constructed CachePruningPolicy object.
47 /// For example: "prune_interval=30s:prune_after=24h:cache_size=50%"
48 /// which means a pruning interval of 30 seconds, expiration time of 24 hours
49 /// and maximum cache size of 50% of available disk space.
50 Expected parseCachePruningPolicy(StringRef PolicyStr);
4051
4152 /// Peform pruning using the supplied policy, returns true if pruning
4253 /// occured, i.e. if Policy.Interval was expired.
1414
1515 #include "llvm/Support/Debug.h"
1616 #include "llvm/Support/Errc.h"
17 #include "llvm/Support/Error.h"
1718 #include "llvm/Support/FileSystem.h"
1819 #include "llvm/Support/Path.h"
1920 #include "llvm/Support/raw_ostream.h"
3031 static void writeTimestampFile(StringRef TimestampFile) {
3132 std::error_code EC;
3233 raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::F_None);
34 }
35
36 static Expected parseDuration(StringRef Duration) {
37 if (Duration.empty())
38 return make_error("Duration must not be empty",
39 inconvertibleErrorCode());
40
41 StringRef NumStr = Duration.slice(0, Duration.size()-1);
42 uint64_t Num;
43 if (NumStr.getAsInteger(0, Num))
44 return make_error("'" + NumStr + "' not an integer",
45 inconvertibleErrorCode());
46
47 switch (Duration.back()) {
48 case 's':
49 return std::chrono::seconds(Num);
50 case 'm':
51 return std::chrono::minutes(Num);
52 case 'h':
53 return std::chrono::hours(Num);
54 default:
55 return make_error("'" + Duration +
56 "' must end with one of 's', 'm' or 'h'",
57 inconvertibleErrorCode());
58 }
59 }
60
61 Expected
62 llvm::parseCachePruningPolicy(StringRef PolicyStr) {
63 CachePruningPolicy Policy;
64 std::pair P = {"", PolicyStr};
65 while (!P.second.empty()) {
66 P = P.second.split(':');
67
68 StringRef Key, Value;
69 std::tie(Key, Value) = P.first.split('=');
70 if (Key == "prune_interval") {
71 auto DurationOrErr = parseDuration(Value);
72 if (!DurationOrErr)
73 return std::move(DurationOrErr.takeError());
74 Policy.Interval = *DurationOrErr;
75 } else if (Key == "prune_after") {
76 auto DurationOrErr = parseDuration(Value);
77 if (!DurationOrErr)
78 return std::move(DurationOrErr.takeError());
79 Policy.Expiration = *DurationOrErr;
80 } else if (Key == "cache_size") {
81 if (Value.back() != '%')
82 return make_error("'" + Value + "' must be a percentage",
83 inconvertibleErrorCode());
84 StringRef SizeStr = Value.slice(0, Value.size() - 1);
85 uint64_t Size;
86 if (SizeStr.getAsInteger(0, Size))
87 return make_error("'" + SizeStr + "' not an integer",
88 inconvertibleErrorCode());
89 if (Size > 100)
90 return make_error("'" + SizeStr +
91 "' must be between 0 and 100",
92 inconvertibleErrorCode());
93 Policy.PercentageOfAvailableSpace = Size;
94 } else {
95 return make_error("Unknown key: '" + Key + "'",
96 inconvertibleErrorCode());
97 }
98 }
99
100 return Policy;
33101 }
34102
35103 /// Prune the cache of files that haven't been accessed in a long time.
99 BinaryStreamTest.cpp
1010 BlockFrequencyTest.cpp
1111 BranchProbabilityTest.cpp
12 CachePruningTest.cpp
1213 Casting.cpp
1314 Chrono.cpp
1415 CommandLineTest.cpp
0 //===- CachePruningTest.cpp -----------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/CachePruning.h"
10 #include "llvm/Support/Error.h"
11 #include "gtest/gtest.h"
12
13 using namespace llvm;
14
15 TEST(CachePruningPolicyParser, Empty) {
16 auto P = parseCachePruningPolicy("");
17 ASSERT_TRUE(bool(P));
18 EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
19 EXPECT_EQ(std::chrono::hours(7 * 24), P->Expiration);
20 EXPECT_EQ(75u, P->PercentageOfAvailableSpace);
21 }
22
23 TEST(CachePruningPolicyParser, Interval) {
24 auto P = parseCachePruningPolicy("prune_interval=1s");
25 ASSERT_TRUE(bool(P));
26 EXPECT_EQ(std::chrono::seconds(1), P->Interval);
27 P = parseCachePruningPolicy("prune_interval=2m");
28 ASSERT_TRUE(bool(P));
29 EXPECT_EQ(std::chrono::minutes(2), P->Interval);
30 P = parseCachePruningPolicy("prune_interval=3h");
31 ASSERT_TRUE(bool(P));
32 EXPECT_EQ(std::chrono::hours(3), P->Interval);
33 }
34
35 TEST(CachePruningPolicyParser, Expiration) {
36 auto P = parseCachePruningPolicy("prune_after=1s");
37 ASSERT_TRUE(bool(P));
38 EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
39 }
40
41 TEST(CachePruningPolicyParser, PercentageOfAvailableSpace) {
42 auto P = parseCachePruningPolicy("cache_size=100%");
43 ASSERT_TRUE(bool(P));
44 EXPECT_EQ(100u, P->PercentageOfAvailableSpace);
45 }
46
47 TEST(CachePruningPolicyParser, Multiple) {
48 auto P = parseCachePruningPolicy("prune_after=1s:cache_size=50%");
49 ASSERT_TRUE(bool(P));
50 EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
51 EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
52 EXPECT_EQ(50u, P->PercentageOfAvailableSpace);
53 }
54
55 TEST(CachePruningPolicyParser, Errors) {
56 EXPECT_EQ("Duration must not be empty",
57 toString(parseCachePruningPolicy("prune_interval=").takeError()));
58 EXPECT_EQ("'foo' not an integer",
59 toString(parseCachePruningPolicy("prune_interval=foos").takeError()));
60 EXPECT_EQ("'24x' must end with one of 's', 'm' or 'h'",
61 toString(parseCachePruningPolicy("prune_interval=24x").takeError()));
62 EXPECT_EQ("'foo' must be a percentage",
63 toString(parseCachePruningPolicy("cache_size=foo").takeError()));
64 EXPECT_EQ("'foo' not an integer",
65 toString(parseCachePruningPolicy("cache_size=foo%").takeError()));
66 EXPECT_EQ("'101' must be between 0 and 100",
67 toString(parseCachePruningPolicy("cache_size=101%").takeError()));
68 EXPECT_EQ("Unknown key: 'foo'",
69 toString(parseCachePruningPolicy("foo=bar").takeError()));
70 }