Chromium Code Reviews| Index: chrome/browser/chromeos/arc/arc_low_memory_killer_monitor.cc |
| diff --git a/chrome/browser/chromeos/arc/arc_low_memory_killer_monitor.cc b/chrome/browser/chromeos/arc/arc_low_memory_killer_monitor.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..517d8471e9b1f904845dde8f3e6404a64a52219e |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/arc/arc_low_memory_killer_monitor.cc |
| @@ -0,0 +1,116 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/arc/arc_low_memory_killer_monitor.h" |
| + |
| +#include <fcntl.h> |
| +#include <vector> |
| + |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "base/logging.h" |
| +#include "base/metrics/histogram_macros.h" |
| +#include "base/sequenced_task_runner.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/time/time.h" |
| +#include "third_party/re2/src/re2/re2.h" |
| + |
| +namespace arc { |
| + |
| +using base::SequencedWorkerPool; |
| +using base::StringPiece; |
| +using base::TimeDelta; |
| + |
| +#define MAX_LOWMEMORYKILL_TIME_SECS 30 |
| +#define UMA_HISTOGRAM_LOWMEMORYKILL_TIMES(name, sample) \ |
| + UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| + name, sample, base::TimeDelta::FromMilliseconds(1), \ |
| + base::TimeDelta::FromSeconds(MAX_LOWMEMORYKILL_TIME_SECS), 50) |
| + |
| +ArcLowMemoryKillerMonitor::ArcLowMemoryKillerMonitor() |
| + : worker_pool_( |
| + new SequencedWorkerPool(1, "arc_low_memory_killer_monitor")), |
| + weak_ptr_factory_(this) {} |
| + |
| +ArcLowMemoryKillerMonitor::~ArcLowMemoryKillerMonitor() { |
| + Stop(); |
| +} |
| + |
| +void ArcLowMemoryKillerMonitor::Start() { |
| + auto task_runner = worker_pool_->GetTaskRunnerWithShutdownBehavior( |
| + SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); |
| + task_runner->PostTask( |
| + FROM_HERE, |
| + base::Bind(&ArcLowMemoryKillerMonitor::Run, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void ArcLowMemoryKillerMonitor::Stop() { |
| + worker_pool_->Shutdown(); |
| +} |
| + |
| +void ArcLowMemoryKillerMonitor::Run() { |
| + // Keep a reference to worker_pool_ in case |this| is deleted in |
| + // shutdown process while this thread returns from a blocking read. |
| + scoped_refptr<SequencedWorkerPool> worker_pool(worker_pool_); |
|
Yusuke Sato
2016/03/14 18:02:12
please remove this and modify the Bind code if you
cylee1
2016/03/15 12:49:15
Done.
|
| + |
| + static const int kMaxBufSize = 512; |
| + |
| + FILE* kmsg_handle = fopen("/dev/kmsg", "r"); |
|
Yusuke Sato
2016/03/14 18:02:12
If you really want to go with FILE, that's fine, b
cylee1
2016/03/15 12:49:15
Ah sorry I'm not familiar with base/files so misse
|
| + char buf[kMaxBufSize]; |
| + int freed_size; |
| + int64_t timestamp, last_timestamp = -1; |
| + const TimeDelta kMaxTimeDelta = TimeDelta::FromSeconds( |
| + MAX_LOWMEMORYKILL_TIME_SECS); |
| + |
| + int kmsg_fd = fileno(kmsg_handle); |
| + int flags = fcntl(kmsg_fd, F_GETFL, 0); |
| + // Consume kernel messages prior to the instantiation of this object to avoid |
| + // double reporting. |
| + fcntl(kmsg_fd, F_SETFL, flags | O_NONBLOCK); |
|
Yusuke Sato
2016/03/14 18:02:12
SetNonBlocking()
cylee1
2016/03/15 12:49:15
Done.
|
| + while (fgets(buf, kMaxBufSize, kmsg_handle)) {} |
|
Yusuke Sato
2016/03/14 18:02:12
The code (setting O_NONBLOCK to the underlying fd,
cylee1
2016/03/15 12:49:15
fseek is better, I missed it.
I can't use the time
|
| + |
| + // Switch back to blocking read. |
| + fcntl(kmsg_fd, F_SETFL, flags & ~O_NONBLOCK); |
|
Yusuke Sato
2016/03/14 18:02:12
same
cylee1
2016/03/15 12:49:15
Done.
|
| + |
| + while (fgets(buf, kMaxBufSize, kmsg_handle)) { |
| + if (worker_pool->IsShutdownInProgress()) { |
| + LOG(WARNING) << "Chrome is shutting down, exit now."; |
| + break; |
| + } |
| + if (RE2::PartialMatch(buf, |
| + "lowmemorykiller: .* to free (\\d+)kB", |
| + &freed_size)) { |
| + std::vector<StringPiece> fields = SplitStringPiece( |
| + buf, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| + |
| + // The time to last kill event. Could be |kMaxTimeDelta| in case of the |
| + // first kill event. |
| + TimeDelta time_delta(kMaxTimeDelta); |
| + // Timestamp is the third field in a line of /dev/kmsg. |
| + // |
| + // Sample log line: |
| + // 6,2302,533604004,-;lowmemorykiller: Killing 'externalstorage' (21742), |
| + // adj 1000,\x0a to free 27320kB on behalf of 'kswapd0' (47) because\x0a |
| + // cache 181920kB is below limit 184320kB for oom_score_adj 1000\x0a |
| + // Free memory is 1228kB above reserved |
| + if (fields.size() >= 3) { |
| + base::StringToInt64(fields[2], ×tamp); |
| + if (last_timestamp > 0) { |
| + time_delta = TimeDelta::FromMicroseconds(timestamp - last_timestamp); |
| + } |
| + last_timestamp = timestamp; |
| + |
| + UMA_HISTOGRAM_MEMORY_KB( |
| + "ArcRuntime.LowMemoryKiller.FreedSize", freed_size); |
| + UMA_HISTOGRAM_LOWMEMORYKILL_TIMES( |
| + "ArcRuntime.LowMemoryKiller.TimeDelta", time_delta); |
| + } |
| + } |
| + } |
| + fclose(kmsg_handle); |
|
Yusuke Sato
2016/03/14 18:02:12
CloseFile()
cylee1
2016/03/15 18:26:57
Done.
|
| +} |
| + |
| +} // namespace arc |