Introduce target dirty segment ratio tunable parameter

We introduce a new parameter of target dirty segment ratio,
which can be used to set a target dirty / (dirty + free) segments
ratio. For example, if we set this as 80%, GC sleep time will be
calculated to achieve this ratio in a GC period.

Bug: 241601436
Test: check smart idle maint log of StorageManagerService
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Change-Id: I73f2bcf4bdb810164c174bd0d2518b15d577d5d5
Merged-In: I73f2bcf4bdb810164c174bd0d2518b15d577d5d5
diff --git a/IdleMaint.cpp b/IdleMaint.cpp
index 1e0ef81..0c6b115 100644
--- a/IdleMaint.cpp
+++ b/IdleMaint.cpp
@@ -508,9 +508,10 @@
 }
 
 void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
-                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime) {
+                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime,
+                     int32_t targetDirtyRatio) {
     std::list<std::string> paths;
-    bool needGC = true;
+    bool needGC = false;
     int32_t sleepTime;
 
     addFromFstab(&paths, PathTypes::kBlkDevice, true);
@@ -553,25 +554,36 @@
     int32_t reservedBlocks = std::stoi(ovpSegmentsStr) + std::stoi(reservedBlocksStr);
 
     freeSegments = freeSegments > reservedBlocks ? freeSegments - reservedBlocks : 0;
-    neededSegments *= reclaimWeight;
-    if (freeSegments >= neededSegments) {
-        LOG(INFO) << "Enough free segments: " << freeSegments
-                   << ", needed segments: " << neededSegments;
-        needGC = false;
-    } else if (freeSegments + dirtySegments < minSegmentThreshold) {
+    int32_t totalSegments = freeSegments + dirtySegments;
+    int32_t finalTargetSegments = 0;
+
+    if (totalSegments < minSegmentThreshold) {
         LOG(INFO) << "The sum of free segments: " << freeSegments
-                   << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
-        needGC = false;
+                  << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
     } else {
-        neededSegments -= freeSegments;
-        neededSegments = std::min(neededSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
-        if (neededSegments == 0) {
-            LOG(INFO) << "Low dirty segments: " << dirtySegments;
-            needGC = false;
+        int32_t dirtyRatio = dirtySegments * 100 / totalSegments;
+        int32_t neededForTargetRatio =
+                (dirtyRatio > targetDirtyRatio)
+                        ? totalSegments * (dirtyRatio - targetDirtyRatio) / 100
+                        : 0;
+        neededSegments *= reclaimWeight;
+        neededSegments = (neededSegments > freeSegments) ? neededSegments - freeSegments : 0;
+
+        finalTargetSegments = std::max(neededSegments, neededForTargetRatio);
+        if (finalTargetSegments == 0) {
+            LOG(INFO) << "Enough free segments: " << freeSegments;
         } else {
-            sleepTime = gcPeriod * ONE_MINUTE_IN_MS / neededSegments;
-            if (sleepTime < minGCSleepTime) {
-                sleepTime = minGCSleepTime;
+            finalTargetSegments =
+                    std::min(finalTargetSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
+            if (finalTargetSegments == 0) {
+                LOG(INFO) << "Low dirty segments: " << dirtySegments;
+            } else if (neededSegments >= neededForTargetRatio) {
+                LOG(INFO) << "Trigger GC, because of needed segments exceeding free segments";
+                needGC = true;
+            } else {
+                LOG(INFO) << "Trigger GC for target dirty ratio diff of: "
+                          << dirtyRatio - targetDirtyRatio;
+                needGC = true;
             }
         }
     }
@@ -583,6 +595,11 @@
         return;
     }
 
+    sleepTime = gcPeriod * ONE_MINUTE_IN_MS / finalTargetSegments;
+    if (sleepTime < minGCSleepTime) {
+        sleepTime = minGCSleepTime;
+    }
+
     if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
         PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
         return;
@@ -594,8 +611,8 @@
     }
 
     LOG(INFO) << "Successfully set gc urgent mode: "
-               << "free segments: " << freeSegments << ", reclaim target: " << neededSegments
-               << ", sleep time: " << sleepTime;
+              << "free segments: " << freeSegments << ", reclaim target: " << finalTargetSegments
+              << ", sleep time: " << sleepTime;
 }
 
 static int32_t getLifeTimeWrite() {