blob: 5b234cd5e01113cf4311a6eaf56d6cf48b4843a4 [file] [log] [blame]
/**
* Copyright 2013, Big Switch Networks, Inc.
*
* 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.
**/
package net.floodlightcontroller.util;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import net.floodlightcontroller.core.annotations.LogMessageDocs;
import net.floodlightcontroller.core.annotations.LogMessageDoc;
public class LoadMonitor implements Runnable {
public enum LoadLevel {
OK,
HIGH,
VERYHIGH,
}
public LoadLevel getLoadLevel() {
return loadlevel ;
}
public double getLoad() {
return load ;
}
public static final int LOADMONITOR_SAMPLING_INTERVAL = 1000; // mili-sec
public static final double THRESHOLD_HIGH = 0.90;
public static final double THRESHOLD_VERYHIGH = 0.95;
public static final int MAX_LOADED_ITERATIONS = 5;
public static final int MAX_LOAD_HISTORY = 5;
protected volatile double load;
protected volatile LoadLevel loadlevel;
protected int itersLoaded;
protected boolean isLinux;
protected int numcores;
protected int jiffyNanos;
protected long[] lastNanos;
protected long[] lastIdle;
protected Logger log;
public LoadMonitor(Logger log_) {
log = log_;
loadlevel = LoadLevel.OK;
load = 0.0;
itersLoaded = 0;
lastNanos = new long[MAX_LOAD_HISTORY];
lastIdle = new long[MAX_LOAD_HISTORY];
for (int i=0 ; i<MAX_LOAD_HISTORY ; i++) {
lastNanos[i] = 0L;
lastIdle[i] = 0L;
}
isLinux = System.getProperty("os.name").equals("Linux");
numcores = 1;
jiffyNanos = 10 * 1000 * 1000;
if (isLinux) {
try {
numcores = Integer.parseInt(
this.runcmd("/usr/bin/nproc"));
jiffyNanos = (1000 * 1000 * 1000) / Integer.parseInt(
this.runcmd("/usr/bin/getconf CLK_TCK"));
}
catch (NumberFormatException ex) {
if (log != null) {
// Log message documented on runcmd function
log.error("Exception in inializing load monitor ", ex);
}
else {
ex.printStackTrace();
}
}
}
}
@Override
@LogMessageDocs({
@LogMessageDoc(
message="System under very heavy load, dropping some packet-ins",
explanation="We detcted that the system was under very heavy" +
" load, dropping some packet-ins temporarily"),
@LogMessageDoc(
message="System under heavy load, dropping some new flows",
explanation="We detcted that the system was under heavy load," +
" dropping some new flows temporarily")
})
public void run() {
if (!isLinux) return;
long currNanos = System.nanoTime();
long currIdle = this.readIdle();
for (int i=0 ; i < (MAX_LOAD_HISTORY - 1) ; i++) {
lastNanos[i] = lastNanos[i+1];
lastIdle[i] = lastIdle[i+1];
}
lastNanos[MAX_LOAD_HISTORY - 1] = currNanos;
lastIdle[MAX_LOAD_HISTORY - 1] = currIdle;
if (itersLoaded >= MAX_LOADED_ITERATIONS) {
loadlevel = LoadLevel.OK;
itersLoaded = 0;
return;
}
long nanos = lastNanos[MAX_LOAD_HISTORY - 1] - lastNanos[0];
long idle = lastIdle[MAX_LOAD_HISTORY - 1] - lastIdle[0];
load =
1.0 - ((double)(idle * jiffyNanos) / (double)(nanos * numcores));
if (load > THRESHOLD_VERYHIGH) {
loadlevel = LoadLevel.VERYHIGH;
itersLoaded += 1;
String msg = "System under very heavy load, dropping packet-ins.";
if (log != null) {
log.error(msg);
}
else {
System.out.println(msg);
}
return;
}
if (load > THRESHOLD_HIGH) {
loadlevel = LoadLevel.HIGH;
itersLoaded += 1;
String msg = "System under heavy load, dropping new flows.";
if (log != null) {
log.error(msg);
}
else {
System.out.println(msg);
}
return;
}
loadlevel = LoadLevel.OK;
itersLoaded = 0;
return;
}
@LogMessageDoc(
message="Exception in reading load monitor params, using defaults",
explanation="There was an error in inializing load monitor's props," +
" using default parameters")
protected String runcmd(String cmd) {
String line;
StringBuilder ret = new StringBuilder();
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader input =
new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
ret.append(line);
}
input.close();
p.waitFor();
}
catch (InterruptedException ex) {
if (log != null) {
log.error("Exception in inializing load monitor ", ex);
}
else {
ex.printStackTrace();
}
}
catch (IOException ex) {
if (log != null) {
log.error("Exception in inializing load monitor ", ex);
}
else {
ex.printStackTrace();
}
}
return ret.toString();
}
protected long readIdle() {
long idle = 0;
FileInputStream fs = null;
BufferedReader reader = null;
try {
try {
fs = new FileInputStream("/proc/stat");
reader = new BufferedReader(new InputStreamReader(fs));
String line = reader.readLine();
if (line == null) throw new IOException("Empty file");
idle = Long.parseLong(line.split("\\s+")[4]);
} finally {
if (reader != null)
reader.close();
if (fs != null)
fs.close();
}
} catch (IOException ex) {
log.error("Error reading idle time from /proc/stat", ex);
}
return idle;
}
public ScheduledFuture<?> startMonitoring(ScheduledExecutorService ses)
{
ScheduledFuture<?> monitorTask =
ses.scheduleAtFixedRate(
this, 0,
LOADMONITOR_SAMPLING_INTERVAL, TimeUnit.MILLISECONDS);
return monitorTask;
}
/*
* For testing
*/
public ScheduledFuture<?> printMonitoring(ScheduledExecutorService ses)
{
final LoadMonitor mon = this;
ScheduledFuture<?> monitorTask =
ses.scheduleAtFixedRate(
new Runnable() {
public void run() {
System.out.println(mon.getLoad());
}
}, LOADMONITOR_SAMPLING_INTERVAL/2,
LOADMONITOR_SAMPLING_INTERVAL, TimeUnit.MILLISECONDS);
return monitorTask;
}
public static void main(String[] args) {
final LoadMonitor monitor = new LoadMonitor(null);
final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> monitorTask =
monitor.startMonitoring(scheduler);
final ScheduledFuture<?> printTask =
monitor.printMonitoring(scheduler);
// Run the tasks for 2 minutes
scheduler.schedule(
new Runnable() {
public void run() {
monitorTask.cancel(true);
printTask.cancel(true);
}
}, 5*60, TimeUnit.SECONDS);
}
}