11f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan/* net/activity_stats.c 21f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 31f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * Copyright (C) 2010 Google, Inc. 41f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 51f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * This software is licensed under the terms of the GNU General Public 61f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * License version 2, as published by the Free Software Foundation, and 71f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * may be copied, distributed, and modified under those terms. 81f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 91f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * This program is distributed in the hope that it will be useful, 101f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * but WITHOUT ANY WARRANTY; without even the implied warranty of 111f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * GNU General Public License for more details. 131f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 141f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * Author: Mike Chan (mike@android.com) 151f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan */ 161f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 171f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan#include <linux/proc_fs.h> 184af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg#include <linux/seq_file.h> 191f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan#include <linux/suspend.h> 201f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan#include <net/net_namespace.h> 211f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 221f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan/* 231f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * Track transmission rates in buckets (power of 2). 241f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 1,2,4,8...512 seconds. 251f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * 261f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * Buckets represent the count of network transmissions at least 271f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * N seconds apart, where N is 1 << bucket index. 281f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan */ 291f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan#define BUCKET_MAX 10 301f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 311f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan/* Track network activity frequency */ 321f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic unsigned long activity_stats[BUCKET_MAX]; 331f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic ktime_t last_transmit; 341f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic ktime_t suspend_time; 351f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic DEFINE_SPINLOCK(activity_lock); 361f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 371f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanvoid activity_stats_update(void) 381f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan{ 391f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan int i; 401f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan unsigned long flags; 411f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan ktime_t now; 421f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan s64 delta; 431f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 441f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan spin_lock_irqsave(&activity_lock, flags); 451f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan now = ktime_get(); 461f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan delta = ktime_to_ns(ktime_sub(now, last_transmit)); 471f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 481f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan for (i = BUCKET_MAX - 1; i >= 0; i--) { 491f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan /* 501f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * Check if the time delta between network activity is within the 511f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan * minimum bucket range. 521f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan */ 531f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan if (delta < (1000000000ULL << i)) 541f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan continue; 551f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 561f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan activity_stats[i]++; 571f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan last_transmit = now; 581f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan break; 591f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan } 601f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan spin_unlock_irqrestore(&activity_lock, flags); 611f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan} 621f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 634af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevågstatic int activity_stats_show(struct seq_file *m, void *v) 641f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan{ 651f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan int i; 664af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg int ret; 671f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 684af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg seq_printf(m, "Min Bucket(sec) Count\n"); 691f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 701f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan for (i = 0; i < BUCKET_MAX; i++) { 714af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg ret = seq_printf(m, "%15d %lu\n", 1 << i, activity_stats[i]); 724af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg if (ret) 734af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg return ret; 741f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan } 751f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 764af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg return 0; 771f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan} 781f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 791f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic int activity_stats_notifier(struct notifier_block *nb, 801f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan unsigned long event, void *dummy) 811f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan{ 821f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan switch (event) { 831f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan case PM_SUSPEND_PREPARE: 841f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan suspend_time = ktime_get_real(); 851f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan break; 861f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 871f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan case PM_POST_SUSPEND: 881f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan suspend_time = ktime_sub(ktime_get_real(), suspend_time); 891f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan last_transmit = ktime_sub(last_transmit, suspend_time); 901f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan } 911f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 921f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan return 0; 931f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan} 941f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 954af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevågstatic int activity_stats_open(struct inode *inode, struct file *file) 964af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg{ 974af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg return single_open(file, activity_stats_show, PDE_DATA(inode)); 984af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg} 994af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg 1004af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevågstatic const struct file_operations activity_stats_fops = { 1014af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg .open = activity_stats_open, 1024af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg .read = seq_read, 1034af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg .llseek = seq_lseek, 1044af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg .release = seq_release, 1054af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg}; 1064af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg 1071f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic struct notifier_block activity_stats_notifier_block = { 1081f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan .notifier_call = activity_stats_notifier, 1091f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan}; 1101f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 1111f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chanstatic int __init activity_stats_init(void) 1121f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan{ 1134af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg proc_create("activity", S_IRUGO, 1144af1c50c2b8d5cb96ee803cc8c8d969708130509Arve Hjønnevåg init_net.proc_net_stat, &activity_stats_fops); 1151f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan return register_pm_notifier(&activity_stats_notifier_block); 1161f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan} 1171f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 1181f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chansubsys_initcall(activity_stats_init); 1191f65785d2b92ccad4ebab8f0b39c9e232d76946fMike Chan 120