diff --git a/hard_sleep.py b/hard_sleep.py new file mode 100755 index 0000000..57e9a91 --- /dev/null +++ b/hard_sleep.py @@ -0,0 +1,119 @@ +#!/usr/bin/python +from collections import OrderedDict +from multiprocessing import Process, Queue +from pprint import pprint +from datetime import datetime +from time import sleep +import argparse +from glob import iglob +import re +import pickle +from subprocess import call +def diskstats_parse(dev=None): + file_path = '/proc/diskstats' + result = {} + + # ref: http://lxr.osuosl.org/source/Documentation/iostats.txt + columns_disk = ['m', 'mm', 'dev', 'reads', 'rd_mrg', 'rd_sectors', + 'ms_reading', 'writes', 'wr_mrg', 'wr_sectors', + 'ms_writing', 'cur_ios', 'ms_doing_io', 'ms_weighted'] + + columns_partition = ['m', 'mm', 'dev', 'reads', 'rd_sectors', 'writes', 'wr_sectors'] + + lines = open(file_path, 'r').readlines() + for line in lines: + if line == '': continue + split = line.split() + if len(split) == len(columns_disk): + columns = columns_disk + elif len(split) == len(columns_partition): + columns = columns_partition + else: + # No match + continue + + data = dict(zip(columns, split)) + if dev != None and dev != data['dev']: + continue + for key in data: + if key != 'dev': + data[key] = int(data[key]) + result[data['dev']] = data + if dev is not None and dev in result: + return result[dev] + else: + return result + +def getRotationals(): + fileRegex =re.compile(r'^\/sys\/block\/([sh]d[\w][\d]*)\/queue\/rotational$') + for files in iglob('/sys/block/[sh]d*/queue/rotational'): + devNameMatcher=fileRegex.match(files) + if devNameMatcher is None: + continue + else: + rotational=False + if open(files,'r').readline().strip()=='1': + yield devNameMatcher.group(1) + else: + continue + raise StopIteration() + +def chooseSleepTarget(target=[]): + if len(target)==0: + return set(disk for disk in getRotationals()) + else: + return set(target).intersection(getRotationals()) +def storeDiskstat(data=diskstats_parse()): + with open('/dev/shm/diskstat', 'wb') as f: + pickle.dump(data,f) +def loadDiskstat(): + with open('/dev/shm/diskstat', 'rb') as f: + return pickle.load(f) + +def chooseActivityDisk(previous,statData): + activityDisks=set(previous.keys()).intersection(statData.keys()) + return set(disk for disk in activityDisks if len(statData[disk].items()- previous[disk].items()) >0) + +def doSleep(disk): + dtStr=datetime.now().ctime() + call(['/usr/bin/logger','-s', "%s %s Sleeping.."%(dtStr,disk)]) + call(['/usr/bin/sg_start','--stop','/dev/%s'%disk]) + #call(['/usr/bin/hdparm','-Y','/dev/%s'%disk]) + #sleep(0.6) + #call(['/usr/bin/hdparm','-Y','/dev/%s'%disk]) + #call(['/bin/sh', '-c', 'echo %s'%disk]) + #sleep(5) + +def processSleepies(sleepies): + for disk in sleepies: + p = Process(target=doSleep, args=(disk,)) + p.start() + yield p + raise StopIteration() + +def entry(): + parser = argparse.ArgumentParser(description='Sleep Rotational Disks') + parser.add_argument('devices', metavar='DEV', type=str, nargs='*', + help='[Default:All rotational Disks]') + parser.add_argument('-n', '--now', dest='now', action='store_true', + help='Sleep Rotationals without IO activity') + args = vars(parser.parse_args()) + + prevStatData=loadDiskstat() + statData=diskstats_parse() + + target=chooseSleepTarget(args['devices']) + if args['now']: + isSleepProcessed=[processed for processed in processSleepies(target)] + for p in isSleepProcessed: + p.join() + else: + activities=chooseActivityDisk(prevStatData,statData) + sleepies=target - activities + isSleepProcessed=[processed for processed in processSleepies(sleepies)] + for p in isSleepProcessed: + p.join() + storeDiskstat(statData) + +if __name__ == '__main__': + entry() diff --git a/hard_sleep.sh b/hard_sleep.sh new file mode 100755 index 0000000..d7f8299 --- /dev/null +++ b/hard_sleep.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Declare an array of delimited parameters. +ARRAY=(${@}) + +# Declare a numeric constant of array elements. +ELEMENTS=${#ARRAY[@]} + +# Does the parameter account agree with array elements. +#if [[ ${#} = ${#ARRAY[@]} ]]; then +# echo "Parameters match exploded array elements." +#else +# echo "Parameters ["${#}"] don't match exploded array elements ["${ELEMENTS}"]." +#fi +# +## Echo line break. +#echo "" +# +# Echo the parameter list. +. /etc/profile +function log_stat { + if [ ! -f /dev/shm/1 ] ; + then + touch /dev/shm/1 /dev/shm/2 + fi + mv /dev/shm/1 /dev/shm/2 + cat /proc/diskstats > /dev/shm/1 +} + +function sleep_check { + HD=$1 + if [ "$(diff /dev/shm/1 /dev/shm/2 | grep $HD )" = "" ] ; + then + logger -s "$(date -R) $HD Sleeping.." +# /usr/bin/sg_start --stop /dev/$HD & + /usr/bin/hdparm -Y /dev/$HD + /usr/bin/sleep 0.6 + /usr/bin/hdparm -Y /dev/$HD + fi +} +log_stat +for (( i = 0; i < ${ELEMENTS}; i++ )); do +# echo " ARRAY["${i}"]=["${ARRAY[${i}]}"]" + sleep_check ${ARRAY[${i}]} & +done