You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
8.8 KiB
236 lines
8.8 KiB
4 months ago
|
/**
|
||
|
* Copyright (c) 2020, The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#ifndef CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
|
||
|
#define CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
|
||
|
|
||
|
#include "PackageInfoResolver.h"
|
||
|
#include "ProcDiskStats.h"
|
||
|
#include "ProcPidStat.h"
|
||
|
#include "ProcStat.h"
|
||
|
#include "UidIoStats.h"
|
||
|
#include "WatchdogPerfService.h"
|
||
|
|
||
|
#include <android-base/result.h>
|
||
|
#include <cutils/multiuser.h>
|
||
|
#include <gtest/gtest_prod.h>
|
||
|
#include <utils/Errors.h>
|
||
|
#include <utils/Mutex.h>
|
||
|
#include <utils/RefBase.h>
|
||
|
|
||
|
#include <ctime>
|
||
|
#include <string>
|
||
|
#include <unordered_set>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace android {
|
||
|
namespace automotive {
|
||
|
namespace watchdog {
|
||
|
|
||
|
// Number of periodic collection perf data snapshots to cache in memory.
|
||
|
const int32_t kDefaultPeriodicCollectionBufferSize = 180;
|
||
|
constexpr const char* kEmptyCollectionMessage = "No collection recorded\n";
|
||
|
|
||
|
// Performance data collected from the `/proc/uid_io/stats` file.
|
||
|
struct UidIoPerfData {
|
||
|
struct Stats {
|
||
|
userid_t userId = 0;
|
||
|
std::string packageName;
|
||
|
int64_t bytes[UID_STATES];
|
||
|
int64_t fsync[UID_STATES];
|
||
|
};
|
||
|
std::vector<Stats> topNReads = {};
|
||
|
std::vector<Stats> topNWrites = {};
|
||
|
int64_t total[METRIC_TYPES][UID_STATES] = {{0}};
|
||
|
};
|
||
|
|
||
|
std::string toString(const UidIoPerfData& perfData);
|
||
|
|
||
|
// Performance data collected from the `/proc/stats` file.
|
||
|
struct SystemIoPerfData {
|
||
|
uint64_t cpuIoWaitTime = 0;
|
||
|
uint64_t totalCpuTime = 0;
|
||
|
uint32_t ioBlockedProcessesCnt = 0;
|
||
|
uint32_t totalProcessesCnt = 0;
|
||
|
};
|
||
|
|
||
|
std::string toString(const SystemIoPerfData& perfData);
|
||
|
|
||
|
// Performance data collected from the `/proc/[pid]/stat` and `/proc/[pid]/task/[tid]/stat` files.
|
||
|
struct ProcessIoPerfData {
|
||
|
struct UidStats {
|
||
|
userid_t userId = 0;
|
||
|
std::string packageName;
|
||
|
uint64_t count = 0;
|
||
|
struct ProcessStats {
|
||
|
std::string comm = "";
|
||
|
uint64_t count = 0;
|
||
|
};
|
||
|
std::vector<ProcessStats> topNProcesses = {};
|
||
|
};
|
||
|
std::vector<UidStats> topNIoBlockedUids = {};
|
||
|
// Total # of tasks owned by each UID in |topNIoBlockedUids|.
|
||
|
std::vector<uint64_t> topNIoBlockedUidsTotalTaskCnt = {};
|
||
|
std::vector<UidStats> topNMajorFaultUids = {};
|
||
|
uint64_t totalMajorFaults = 0;
|
||
|
// Percentage of increase/decrease in the major page faults since last collection.
|
||
|
double majorFaultsPercentChange = 0.0;
|
||
|
};
|
||
|
|
||
|
std::string toString(const ProcessIoPerfData& data);
|
||
|
|
||
|
struct IoPerfRecord {
|
||
|
time_t time; // Collection time.
|
||
|
UidIoPerfData uidIoPerfData;
|
||
|
SystemIoPerfData systemIoPerfData;
|
||
|
ProcessIoPerfData processIoPerfData;
|
||
|
};
|
||
|
|
||
|
std::string toString(const IoPerfRecord& record);
|
||
|
|
||
|
struct CollectionInfo {
|
||
|
size_t maxCacheSize = 0; // Maximum cache size for the collection.
|
||
|
std::vector<IoPerfRecord> records; // Cache of collected performance records.
|
||
|
};
|
||
|
|
||
|
std::string toString(const CollectionInfo& collectionInfo);
|
||
|
|
||
|
// Forward declaration for testing use only.
|
||
|
namespace internal {
|
||
|
|
||
|
class IoPerfCollectionPeer;
|
||
|
|
||
|
} // namespace internal
|
||
|
|
||
|
// IoPerfCollection implements the I/O performance data collection module.
|
||
|
class IoPerfCollection : public IDataProcessorInterface {
|
||
|
public:
|
||
|
IoPerfCollection() :
|
||
|
mTopNStatsPerCategory(0),
|
||
|
mTopNStatsPerSubcategory(0),
|
||
|
mPackageInfoResolver(PackageInfoResolver::getInstance()),
|
||
|
mBoottimeCollection({}),
|
||
|
mPeriodicCollection({}),
|
||
|
mCustomCollection({}),
|
||
|
mLastMajorFaults(0) {}
|
||
|
|
||
|
~IoPerfCollection() { terminate(); }
|
||
|
|
||
|
std::string name() { return "IoPerfCollection"; }
|
||
|
|
||
|
// Implements IDataProcessorInterface.
|
||
|
android::base::Result<void> onBoottimeCollection(time_t time,
|
||
|
const android::wp<UidIoStats>& uidIoStats,
|
||
|
const android::wp<ProcStat>& procStat,
|
||
|
const android::wp<ProcPidStat>& procPidStat);
|
||
|
|
||
|
android::base::Result<void> onPeriodicCollection(time_t time, SystemState systemState,
|
||
|
const android::wp<UidIoStats>& uidIoStats,
|
||
|
const android::wp<ProcStat>& procStat,
|
||
|
const android::wp<ProcPidStat>& procPidStat);
|
||
|
|
||
|
android::base::Result<void> onCustomCollection(
|
||
|
time_t time, SystemState systemState,
|
||
|
const std::unordered_set<std::string>& filterPackages,
|
||
|
const android::wp<UidIoStats>& uidIoStats, const android::wp<ProcStat>& procStat,
|
||
|
const android::wp<ProcPidStat>& procPidStat);
|
||
|
|
||
|
android::base::Result<void> onPeriodicMonitor(
|
||
|
[[maybe_unused]] time_t time,
|
||
|
[[maybe_unused]] const android::wp<IProcDiskStatsInterface>& procDiskStats,
|
||
|
[[maybe_unused]] const std::function<void()>& alertHandler) {
|
||
|
// No monitoring done here as this DataProcessor only collects I/O performance records.
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
android::base::Result<void> onDump(int fd);
|
||
|
|
||
|
android::base::Result<void> onCustomCollectionDump(int fd);
|
||
|
|
||
|
protected:
|
||
|
android::base::Result<void> init();
|
||
|
|
||
|
// Clears in-memory cache.
|
||
|
void terminate();
|
||
|
|
||
|
private:
|
||
|
// Processes the collected data.
|
||
|
android::base::Result<void> processLocked(time_t time,
|
||
|
const std::unordered_set<std::string>& filterPackages,
|
||
|
const android::wp<UidIoStats>& uidIoStats,
|
||
|
const android::wp<ProcStat>& procStat,
|
||
|
const android::wp<ProcPidStat>& procPidStat,
|
||
|
CollectionInfo* collectionInfo);
|
||
|
|
||
|
// Processes performance data from the `/proc/uid_io/stats` file.
|
||
|
void processUidIoPerfData(const std::unordered_set<std::string>& filterPackages,
|
||
|
const android::wp<UidIoStats>& uidIoStats,
|
||
|
UidIoPerfData* uidIoPerfData) const;
|
||
|
|
||
|
// Processes performance data from the `/proc/stats` file.
|
||
|
void processSystemIoPerfData(const android::wp<ProcStat>& procStat,
|
||
|
SystemIoPerfData* systemIoPerfData) const;
|
||
|
|
||
|
// Processes performance data from the `/proc/[pid]/stat` and `/proc/[pid]/task/[tid]/stat`
|
||
|
// files.
|
||
|
void processProcessIoPerfDataLocked(const std::unordered_set<std::string>& filterPackages,
|
||
|
const android::wp<ProcPidStat>& procPidStat,
|
||
|
ProcessIoPerfData* processIoPerfData);
|
||
|
|
||
|
// Top N per-UID stats per category.
|
||
|
int mTopNStatsPerCategory;
|
||
|
|
||
|
// Top N per-process stats per subcategory.
|
||
|
int mTopNStatsPerSubcategory;
|
||
|
|
||
|
// Local IPackageInfoResolver instance. Useful to mock in tests.
|
||
|
sp<IPackageInfoResolver> mPackageInfoResolver;
|
||
|
|
||
|
// Makes sure only one collection is running at any given time.
|
||
|
Mutex mMutex;
|
||
|
|
||
|
// Info for the boot-time collection event. The cache is persisted until system shutdown/reboot.
|
||
|
CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
|
||
|
|
||
|
// Info for the periodic collection event. The cache size is limited by
|
||
|
// |ro.carwatchdog.periodic_collection_buffer_size|.
|
||
|
CollectionInfo mPeriodicCollection GUARDED_BY(mMutex);
|
||
|
|
||
|
// Info for the custom collection event. The info is cleared at the end of every custom
|
||
|
// collection.
|
||
|
CollectionInfo mCustomCollection GUARDED_BY(mMutex);
|
||
|
|
||
|
// Major faults delta from last collection. Useful when calculating the percentage change in
|
||
|
// major faults since last collection.
|
||
|
uint64_t mLastMajorFaults GUARDED_BY(mMutex);
|
||
|
|
||
|
friend class WatchdogPerfService;
|
||
|
|
||
|
// For unit tests.
|
||
|
friend class internal::IoPerfCollectionPeer;
|
||
|
FRIEND_TEST(IoPerfCollectionTest, TestUidIoStatsGreaterThanTopNStatsLimit);
|
||
|
FRIEND_TEST(IoPerfCollectionTest, TestUidIOStatsLessThanTopNStatsLimit);
|
||
|
FRIEND_TEST(IoPerfCollectionTest, TestProcessSystemIoPerfData);
|
||
|
FRIEND_TEST(IoPerfCollectionTest, TestProcPidContentsGreaterThanTopNStatsLimit);
|
||
|
FRIEND_TEST(IoPerfCollectionTest, TestProcPidContentsLessThanTopNStatsLimit);
|
||
|
};
|
||
|
|
||
|
} // namespace watchdog
|
||
|
} // namespace automotive
|
||
|
} // namespace android
|
||
|
|
||
|
#endif // CPP_WATCHDOG_SERVER_SRC_IOPERFCOLLECTION_H_
|