blob: 57c2b1740647b7d466a2438afbe40da55b8420bf [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.
#include "starboard/system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <unistd.h>
#include "starboard/file.h"
#include "starboard/log.h"
#include "starboard/string.h"
// We find the current amount of used memory on Linux by opening
// '/proc/self/status' and scan the file for its "VmRSS" entry. Essentially,
// we need to parse a buffer that has the following format:
//
// xxxxxx: 45327 kB
// yyyyyy: 23 kB
// VmRSS: 87432 kB
// zzzzzz: 3213 kB
// ...
//
// And here, we would want to return the value 87432 * 1024.
// See http://man7.org/linux/man-pages/man5/proc.5.html for more details.
// Searches for the value of VmRSS and returns it. Will modify |buffer| in
// order to do so quickly and easily.
int64_t SearchForVmRSSValue(char* buffer, size_t length) {
// Search for the string ""VmRSS:".
const char kSearchString[] = "\nVmRSS:";
enum State {
// We are currently searching for kSearchString
kSearchingForSearchString,
// We found the search string and are advancing through spaces/tabs until
// we see a number.
kAdvancingSpacesToNumber,
// We found the number and are now searching for the end of it.
kFindingEndOfNumber,
};
State state = kSearchingForSearchString;
const char* number_start = NULL;
for (size_t i = 0; i < length - sizeof(kSearchString); ++i) {
if (state == kSearchingForSearchString) {
if (SbStringCompare(&buffer[i], kSearchString,
sizeof(kSearchString) - 1) == 0) {
// Advance until we find a number.
state = kAdvancingSpacesToNumber;
i += sizeof(kSearchString) - 2;
}
} else if (state == kAdvancingSpacesToNumber) {
if (buffer[i] >= '0' && buffer[i] <= '9') {
// We found the start of the number, record where that is and then
// continue searching for the end of the number.
number_start = &buffer[i];
state = kFindingEndOfNumber;
}
} else {
SB_DCHECK(state == kFindingEndOfNumber);
if (buffer[i] < '0' || buffer[i] > '9') {
// Drop a null at the end of the number so that we can call atoi() on
// it and return.
buffer[i] = '\0';
return SbStringAToI(number_start);
}
}
}
SB_LOG(ERROR) << "Could not find 'VmRSS:' in /proc/self/status.";
return 0;
}
int64_t SbSystemGetUsedCPUMemory() {
// Read our process' current physical memory usage from /proc/self/status.
// This requires a bit of parsing through the output to find the value for
// the "VmRSS" field which indicates used physical memory.
starboard::ScopedFile status_file("/proc/self/status",
kSbFileOpenOnly | kSbFileRead);
if (!status_file.IsValid()) {
SB_LOG(ERROR)
<< "Error opening /proc/self/status in order to query self memory "
"usage.";
return 0;
}
// Read the entire file into memory.
const int kBufferSize = 2048;
char buffer[kBufferSize];
int remaining = kBufferSize;
char* output_pointer = buffer;
do {
int result = status_file.Read(output_pointer, remaining);
if (result <= 0)
break;
remaining -= result;
output_pointer += result;
} while (remaining);
// Return the result, multiplied by 1024 because it is given in kilobytes.
return SearchForVmRSSValue(buffer,
static_cast<size_t>(output_pointer - buffer)) *
1024;
}