mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 00:45:18 +03:00
a5c85ec822
Summary: Most of the RequestData code is platform generic, but bits of it are currently strongly tied to FUSE. By splitting these 2 parts, we will be able to use the RequestContext class in Windows too and not having to re-implement all the logic there. Reviewed By: chadaustin Differential Revision: D23482072 fbshipit-source-id: 857fd9ca4264d0f308ec10cc487e9ff3eeb5ee16
109 lines
3.0 KiB
C++
109 lines
3.0 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <folly/Synchronized.h>
|
|
#include <type_traits>
|
|
|
|
#include "eden/fs/service/gen-cpp2/eden_types.h"
|
|
#include "eden/fs/utils/BucketedLog.h"
|
|
#include "eden/fs/utils/EnumValue.h"
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
class ProcessNameCache;
|
|
struct ThreadLocalBucket;
|
|
|
|
/**
|
|
* An inexpensive mechanism for counting accesses by pids. Intended for counting
|
|
* channel and Thrift calls from external processes.
|
|
*
|
|
* The first time a thread calls recordAccess, that thread is then coupled to
|
|
* this particular ProcessAccessLog, even if it calls recordAccess on another
|
|
* ProcessAccessLog instance. Thus, use one ProcessAccessLog per pool of
|
|
* threads.
|
|
*/
|
|
class ProcessAccessLog {
|
|
public:
|
|
enum class AccessType : unsigned int {
|
|
FsChannelRead,
|
|
FsChannelWrite,
|
|
FsChannelOther,
|
|
FsChannelBackingStoreImport,
|
|
Last,
|
|
};
|
|
|
|
explicit ProcessAccessLog(std::shared_ptr<ProcessNameCache> processNameCache);
|
|
~ProcessAccessLog();
|
|
|
|
/**
|
|
* Records an access by a process ID. The first call to recordAccess by a
|
|
* particular thread binds that thread to this access log. Future recordAccess
|
|
* calls on that thread will accumulate within this access log.
|
|
*
|
|
* Process IDs passed to recordAccess are also inserted into the
|
|
* ProcessNameCache.
|
|
*/
|
|
void recordAccess(pid_t pid, AccessType type);
|
|
void recordDuration(pid_t pid, std::chrono::nanoseconds duration);
|
|
|
|
/**
|
|
* Returns the number of times each pid was passed to recordAccess() in
|
|
* `lastNSeconds`.
|
|
*
|
|
* Note: ProcessAccessLog buckets by whole seconds, so this number should be
|
|
* considered an approximation.
|
|
*/
|
|
std::unordered_map<pid_t, AccessCounts> getAccessCounts(
|
|
std::chrono::seconds lastNSeconds);
|
|
|
|
private:
|
|
struct PerBucketAccessCounts {
|
|
size_t counts[enumValue(AccessType::Last)];
|
|
std::chrono::nanoseconds duration;
|
|
|
|
size_t& operator[](AccessType type) {
|
|
static_assert(std::is_unsigned_v<std::underlying_type_t<AccessType>>);
|
|
auto idx = enumValue(type);
|
|
CHECK_LT(idx, enumValue(AccessType::Last));
|
|
return counts[idx];
|
|
}
|
|
};
|
|
|
|
// Data for one second.
|
|
struct Bucket {
|
|
void clear();
|
|
void add(pid_t pid, bool& isNew, AccessType type);
|
|
void add(pid_t pid, bool& isNew, std::chrono::nanoseconds duration);
|
|
void merge(const Bucket& other);
|
|
|
|
std::unordered_map<pid_t, PerBucketAccessCounts> accessCountsByPid;
|
|
};
|
|
|
|
// Keep up to ten seconds of data, but use a power of two so BucketedLog
|
|
// generates smaller, faster code.
|
|
static constexpr uint64_t kBucketCount = 16;
|
|
using Buckets = BucketedLog<Bucket, kBucketCount>;
|
|
|
|
struct State {
|
|
Buckets buckets;
|
|
};
|
|
|
|
const std::shared_ptr<ProcessNameCache> processNameCache_;
|
|
folly::Synchronized<State> state_;
|
|
|
|
uint64_t getSecondsSinceEpoch();
|
|
ThreadLocalBucket* getTlb();
|
|
|
|
friend struct ThreadLocalBucket;
|
|
};
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|