Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
feature request: update hd-idle
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Unsupported Software
View previous topic :: View next topic  
Author Message
jpsollie
Guru
Guru


Joined: 17 Aug 2013
Posts: 323

PostPosted: Tue Apr 18, 2023 6:41 am    Post subject: feature request: update hd-idle Reply with quote

The hd-idle program in the portage tree is quite outdated these days,
where should I put a feature request to build it from a more "modern" source?
I myself tried the one of adelolmo on github (https://github.com/adelolmo/hd-idle.git), and got a few nice config files for openrc:
Code:

#!/sbin/openrc-run
# Copyright 1999-2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

description="Utility for spinning down hard disks after a period of idle time"

command="/usr/local/sbin/hd-idle"
command_args="${HD_IDLE_OPTS}"

depend() {
        after bootmisc
}

start() {
        disks="-i $HD_IDLE_DEFAULT_TIMEOUT -c $HD_IDLE_DEFAULT_PROTO ";
        [ -z "$HD_IDLE_EXCLUSIONS" ] || disks+=$(lsscsi | grep -E "(${HD_IDLE_EXCLUSIONS//\ /\)\(})" | sed 's/.*\/dev\/\(sd.*\)$/-a \1 -i 0 /g') ;
        [ -z "$HD_IDLE_SCSI_TIMEOUT" ] || disks+=$(lsscsi | grep -v -E "(${HD_IDLE_EXCLUSIONS//\ /\)\(})" | grep -v ATA | grep disk | grep -v nvme | sed "s/.*\/dev\/\(sd.*\)$/-a \1 -i ${HD_IDLE_SCSI_TIMEOUT} -c scsi -p 3/g") ;
        [ -z "$HD_IDLE_ATA_TIMEOUT" ] || disks+=$(lsscsi | grep -v -E "(${HD_IDLE_EXCLUSIONS//\ /\)\(})" | grep ATA | grep disk | grep -v nvme | sed "s/.*\/dev\/\(sd.*\)$/-a \1 -i ${HD_IDLE_ATA_TIMEOUT} -c ata -p 0 /g") ;
        HD_IDLE_OPTS="${disks} -l ${HD_LOG_OPTS}"
        start-stop-daemon --start --quiet --oknodo --background --exec $command -- $HD_IDLE_OPTS
}


Code:

#is default protocol sata or scsi?
HD_IDLE_DEFAULT_PROTO="ata"
#timeout (in seconds) for entering powersave of default disks.  0 means do not spin down
HD_IDLE_DEFAULT_TIMEOUT="300"
#timeout (in seconds) for entering powersave of SATA disks.  0 means do not spin down, if default is ata then this value must be empty
HD_IDLE_ATA_TIMEOUT=""
#timeout (in seconds) for entering powersave of SCSI disks.  0 means do not spin down, if default is scsi then this value must be empty
HD_IDLE_SCSI_TIMEOUT="300"
#logfile to write events to
HD_LOG_OPTS="/var/log/hd-idle.log"
#disks which should be omitted from entering powersave.  Model or /dev/sd* are supported, separated by space
HD_IDLE_EXCLUSIONS="ST1000"

_________________
The power of Gentoo optimization (not overclocked): [img]https://www.passmark.com/baselines/V10/images/503714802842.png[/img]
Back to top
View user's profile Send private message
Banana
Moderator
Moderator


Joined: 21 May 2004
Posts: 1729
Location: Germany

PostPosted: Tue Apr 18, 2023 11:28 am    Post subject: Reply with quote

https://bugs.gentoo.org/ even it is not a bug
_________________
Forum Guidelines

PFL - Portage file list - find which package a file or command belongs to.
My delta-labs.org snippets do expire
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22649

PostPosted: Tue Apr 18, 2023 5:27 pm    Post subject: Reply with quote

If you find yourself using both grep and sed together, or multiple chained greps, there is usually an easier way to process the text to get the result you want. Similarly, running lsscsi three times looks questionable.
Back to top
View user's profile Send private message
jpsollie
Guru
Guru


Joined: 17 Aug 2013
Posts: 323

PostPosted: Mon Apr 24, 2023 11:41 am    Post subject: Reply with quote

Hu wrote:
If you find yourself using both grep and sed together, or multiple chained greps, there is usually an easier way to process the text to get the result you want. Similarly, running lsscsi three times looks questionable.

Yes, absolutely. I should consider using lsblk as well to use the info the kernel already has.
However: how would you improve the chained grep problem then? Request sed to drop lines not relevant? or any better option which may be more failsafe?
*EDIT* if you have a suggestion for a more "clean" way of working aside from "try device name or part of model number", it would greatly be appreciated
_________________
The power of Gentoo optimization (not overclocked): [img]https://www.passmark.com/baselines/V10/images/503714802842.png[/img]
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22649

PostPosted: Mon Apr 24, 2023 3:56 pm    Post subject: Reply with quote

Yes, tell sed to delete the lines. To more fully answer your question with a rewrite requires more time than I can spare today. However, I observe that in this case all three pipelines add to the same shell variable, albeit under different guards. This suggests you could have one more complex pipeline that adds to the shell variable once, which would avoid the need for multiple lsscsi calls and possibly even avoid saving its output to a temporary file.
Back to top
View user's profile Send private message
jpsollie
Guru
Guru


Joined: 17 Aug 2013
Posts: 323

PostPosted: Fri Aug 09, 2024 9:51 am    Post subject: Reply with quote

hi everyone,

sorry for reviving this old thread, but I think I got what Hu wanted:

Code:

        disks="-i $HD_IDLE_DEFAULT_TIMEOUT -c $HD_IDLE_DEFAULT_PROTO ";
        #trim the exclusions list
        HD_IDLE_EXCLUSIONS="${HD_IDLE_EXCLUSIONS#\ }"
        HD_IDLE_EXCLUSIONS="${HD_IDLE_EXCLUSIONS%\ }"
        #only consider sata and sas drives, so blacklist usb
        HD_IDLE_EXCLUSIONS+=" usb"
        ignoring_disks=$(lsblk -S -o name,vendor,model,tran | grep -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
        working_disks=$(lsblk -S -o name,vendor,model,tran | grep -v -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
        [[ -z "ignoring_disks" ]] || disks+=$(echo "$ignoring_disks" | sed 's/^\(sd[a-z]*\)[\t\ ].*$/-a \1 -i 0 /g') ;
        [[ -z "$HD_IDLE_ATA_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+ATA.*/-a \1 -i ${HD_IDLE_ATA_TIMEOUT} -c ata -p 0 /p") ;
        [[ -z "$HD_IDLE_SCSI_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+[^\t^\ ^A^T]\{1,3\}.*/-a \1 -i ${HD_IDLE_SCSI_TIMEOUT} -c scsi -p 3 /p") ;
        HD_IDLE_OPTS="${disks} -l ${HD_LOG_OPTS}"
        start-stop-daemon --start --background -1 ${HD_LOG_OPTS} -2 ${HD_LOG_OPTS} --exec $command -- $HD_IDLE_OPTS


@Hu: what do you think of this way-of-working?

*EDIT*: corrected typo in code
_________________
The power of Gentoo optimization (not overclocked): [img]https://www.passmark.com/baselines/V10/images/503714802842.png[/img]
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 22649

PostPosted: Fri Aug 09, 2024 2:23 pm    Post subject: Reply with quote

It is better, but you are still running list commands repeatedly.
jpsollie wrote:
Code:
        ignoring_disks=$(lsblk -S -o name,vendor,model,tran | grep -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
        working_disks=$(lsblk -S -o name,vendor,model,tran | grep -v -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
This is two invocations of lsblk with the same arguments. Using a temporary file, or some cleverness with tee and pipes, could cut it down to one. You could add -n to suppress the header line, which may simplify later logic.

Considering the simple and line-oriented nature of the output, you could even capture the whole lsblk into a shell variable, and filter it later.
Code:
lsblk -n -S -o name,vendor,model,tran | { while read -r found_disk; do
   # found_disk is now one line of output from lsblk.  Break it into
   # pieces, and decide whether to consider the drive ignored or
   # working.
   FIXME - not implemented yet
done; }
I started this post intending to write the body of that while loop for you, but I again find myself without time to finish it. Sorry. If you want to pursue that route, post back and I can try to look at it later.

If you decide to try to write that for yourself, note that I put braces around the loop intentionally. When you pass the close brace, any variables created in that pipeline will be inaccessible, so you need to move all later logic that depends on the lsblk output (which appears to be everything) to occur after the done and before the ; }. For example:
Code:

lsblk $args | while read -r a; do var+="$a"; done
echo "$var" # result of while loop may be lost!

lsblk $args | { while read -r a; do var+="$a"; done; echo "$var"; } # OK, changes from loop are still visible
This is because the shell will (usually) run the right hand side of the pipe in a forked process, so when the statement ends, changes to its variables are lost. The braces give you a compound statement, so you can access variables after the loop but before you exit the forked process.
jpsollie wrote:
Code:
        [[ -z "ignoring_disks" ]] || disks+=$(echo "$ignoring_disks" | sed 's/^\(sd[a-z]*\)[\t\ ].*$/-a \1 -i 0 /g') ;
This will not do what you want, since you test whether the literal string ignoring_disks is empty, and it never is. I think you meant to test whether the value of the variable ignoring_disks is empty.
jpsollie wrote:
Code:
        [[ -z "$HD_IDLE_ATA_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+ATA.*/-a \1 -i ${HD_IDLE_ATA_TIMEOUT} -c ata -p 0 /p") ;
        [[ -z "$HD_IDLE_SCSI_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+[^\t^\ ^A^T]\{1,3\}.*/-a \1 -i ${HD_IDLE_SCSI_TIMEOUT} -c scsi -p 3 /p") ;
These could be combined, by building up the arguments to sed and then running one sed with both expressions.
Back to top
View user's profile Send private message
jpsollie
Guru
Guru


Joined: 17 Aug 2013
Posts: 323

PostPosted: Sat Aug 10, 2024 6:29 pm    Post subject: Reply with quote

Hu wrote:
It is better, but you are still running list commands repeatedly.
jpsollie wrote:
Code:
        ignoring_disks=$(lsblk -S -o name,vendor,model,tran | grep -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
        working_disks=$(lsblk -S -o name,vendor,model,tran | grep -v -E "(${HD_IDLE_EXCLUSIONS// /\)|\(})")
This is two invocations of lsblk with the same arguments. Using a temporary file, or some cleverness with tee and pipes, could cut it down to one. You could add -n to suppress the header line, which may simplify later logic.

Considering the simple and line-oriented nature of the output, you could even capture the whole lsblk into a shell variable, and filter it later.
Code:
lsblk -n -S -o name,vendor,model,tran | { while read -r found_disk; do
   # found_disk is now one line of output from lsblk.  Break it into
   # pieces, and decide whether to consider the drive ignored or
   # working.
   FIXME - not implemented yet
done; }
I started this post intending to write the body of that while loop for you, but I again find myself without time to finish it. Sorry. If you want to pursue that route, post back and I can try to look at it later.

Yes, the idea of switching to lsblk was because it extracts from linux' block system instead of querying hw, like lsscsi does.
As linux already keeps it, the overhead will be insignificant, right? So I thought wasting an extra variabele on it wouldn't be useful.
Quote:

If you decide to try to write that for yourself, note that I put braces around the loop intentionally. When you pass the close brace, any variables created in that pipeline will be inaccessible, so you need to move all later logic that depends on the lsblk output (which appears to be everything) to occur after the done and before the ; }. For example:
Code:

lsblk $args | while read -r a; do var+="$a"; done
echo "$var" # result of while loop may be lost!

lsblk $args | { while read -r a; do var+="$a"; done; echo "$var"; } # OK, changes from loop are still visible
This is because the shell will (usually) run the right hand side of the pipe in a forked process, so when the statement ends, changes to its variables are lost. The braces give you a compound statement, so you can access variables after the loop but before you exit the forked process.

Wouldn't it cause a lot more overhead to use a loop instead of piping everything, like I'm doing now?
Quote:
jpsollie wrote:
Code:
        [[ -z "ignoring_disks" ]] || disks+=$(echo "$ignoring_disks" | sed 's/^\(sd[a-z]*\)[\t\ ].*$/-a \1 -i 0 /g') ;
This will not do what you want, since you test whether the literal string ignoring_disks is empty, and it never is. I think you meant to test whether the value of the variable ignoring_disks is empty.

Yes, absolutely. Sorry, forgot about that
Quote:
jpsollie wrote:
Code:
        [[ -z "$HD_IDLE_ATA_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+ATA.*/-a \1 -i ${HD_IDLE_ATA_TIMEOUT} -c ata -p 0 /p") ;
        [[ -z "$HD_IDLE_SCSI_TIMEOUT" ]] || disks+=$(echo "$working_disks" | sed -n "s/^\(sd[a-z]\+\)[\ \t]\+[^\t^\ ^A^T]\{1,3\}.*/-a \1 -i ${HD_IDLE_SCSI_TIMEOUT} -c scsi -p 3 /p") ;
These could be combined, by building up the arguments to sed and then running one sed with both expressions.
ouch ... That sounds like a hard regex, far beyond my knowledge
_________________
The power of Gentoo optimization (not overclocked): [img]https://www.passmark.com/baselines/V10/images/503714802842.png[/img]
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Unsupported Software All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum