mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
b55e4dbb58
Summary: Add a ProcessAccessLog that supports cheaply tracking pids passed into FUSE. It's a write-many, read-maybe access pattern, so the code is careful to add as little latency as possible on the hot path. Reviewed By: strager Differential Revision: D9477839 fbshipit-source-id: 6928c1d09d55c2b0c0958ac2cb0dc91ec21b370c
89 lines
2.4 KiB
C++
89 lines
2.4 KiB
C++
/*
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
#include <folly/Synchronized.h>
|
|
#include <unistd.h>
|
|
#include <chrono>
|
|
#include "eden/fs/utils/BucketedLog.h"
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
class ProcessNameCache;
|
|
|
|
/**
|
|
* An inexpensive mechanism for counting accesses by pids. Intended for counting
|
|
* FUSE 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:
|
|
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);
|
|
|
|
/**
|
|
* 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, size_t> getAllAccesses(
|
|
std::chrono::seconds lastNSeconds);
|
|
|
|
private:
|
|
// Data for one second.
|
|
struct Bucket {
|
|
void clear();
|
|
|
|
/**
|
|
* Returns whether the added pid is newly observed or not in the `isNew` out
|
|
* parameter.
|
|
*/
|
|
void add(pid_t pid, bool& isNew);
|
|
|
|
void merge(const Bucket& other);
|
|
|
|
std::unordered_map<pid_t, size_t> accessCounts;
|
|
};
|
|
|
|
// 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_;
|
|
|
|
friend struct ThreadLocalBucket;
|
|
};
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|