LINUX.ORG.RU

Следить за изменением псевдофайла в /proc

 


1

3

Ситуация такая, что есть скрипт на bash, который грепает строчку в псевдофайле в /proc и в зависимости от значения выполняет команду. Проблема в том, что это значение 95% времени одинаковое, а команда все-равно выполняется все время. inotify как выяснилось не может в /proc, может есть способ накостылять что-то с проверкой контрольных сумм? Что подскажете? Вот скрипт:

#!/bin/bash

do_it(){
    RATE="$(grep -E "rate: .*" /proc/asound/card1/pcm0p/sub0/hw_params | awk '{print $2}')"
    case "${RATE}" in
        44100    ) SET="0" ;;
        48000    ) SET="1" ;;
        88200    ) SET="2" ;;
        96000    ) SET="3" ;;
        176400    ) SET="4" ;;
        192000    ) SET="5" ;;
        *        ) SET="0" ;;
    esac
    amixer -c 1 set 'Clock rate Selector' ${SET}
}

while :; do
        do_it && sleep 0.01
done

★★★

Какой смысл в проверке контрольной суммы всего файла, если интересует только ″rate″? Сохраняйте его предыдущее значение и сравнивайте с ним.

mky ★★★★★
()

sleep 0.01

в данном конкретном случае очень большой оверхед от скриптовых ЯП, особенно bash'а. Несложно это всё переписать на сишку. Задача очень простая, но гонять 100 раз в секунду интерпретатор bash/python/etc это само по себе накладно, какой-бы не был код.

emulek
()
Ответ на: комментарий от emulek

Может быть, но к сожалению я и в баше-то полный нуб, которому вот только недавно понадобилось небольшие скрипты писать, а о сишке и говорить не приходится.

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 1)
Ответ на: комментарий от Andrew

я и в баше-то полный нуб

дык и разница? Объясняю жеж: использовать bash для этого плохо. Если так боишься компиляции, вот это попробуй: http://bellard.org/tcc/

emulek
()

sleep 0.01

Так не делай. У тебя скрипт процессор будет кушать.

Время модификации файла разве не меняется при апдейте?

Kroz ★★★★★
()

Пиши на perl, чтобы один раз запустить и дальше крути проверку в цикле. Можно и на bash, но так чтобы не использовать внешние утилиты и тоже запустить один раз и пусть крутится во внутреннем цикле.

sdio ★★★★★
()
Ответ на: комментарий от Kroz

Время модификации файла разве не меняется при апдейте?

В /proc? Меняется, но не так как ты ожидаешь.

sdio ★★★★★
()

Я бы вместо этого посмотрел, нет ли у алсы API, через которое это можно повесить колбек на изменение этого rate.

fmdw
()
Ответ на: комментарий от emulek

но гонять 100 раз в секунду интерпретатор bash/python/etc это само по себе накладно

Он не гоняет bash. grep и awk гоняет, но их можно не использовать, а заменить на башевые аналоги while read line; .... done </proc/file и т.д.

sdio ★★★★★
()
Ответ на: комментарий от Kroz

Так не делай. У тебя скрипт процессор будет кушать.

А как делать? Мне нужно, чтобы проверка выполнялась именно постоянно, выше этого значения уже не пойдет.

Время модификации файла разве не меняется при апдейте?

Это не реальный файл. Чтение из этого файла — это запрос ядру, который отвечает на этот запрос.

Andrew ★★★
() автор топика

полагаю, что сам подход к проблеме неверный. Ты, как бы, пытаешься выкопать траншею при помощи лома, а жалуешься на то, что лом очень тяжелый и нет ли у кого лома полегче )))

chg ★★★★★
()
Ответ на: комментарий от chg

Есть идеи лучше? Ну предлагай тогда.

Andrew ★★★
() автор топика
#!/bin/bash

do_it(){
    case "${RATE}" in
        44100    ) SET="0" ;;
        48000    ) SET="1" ;;
        88200    ) SET="2" ;;
        96000    ) SET="3" ;;
        176400    ) SET="4" ;;
        192000    ) SET="5" ;;
        *        ) SET="0" ;;
    esac
    amixer -c 1 set 'Clock rate Selector' ${SET}
}

RATE=0

while :; do
   while read f1 f2 f3; do
        if [ "$f1" = "rate:" -a "$RATE" -ne "$f2" ]; then
             RATE="$f2"
             do_it
   done  < /proc/asound/card1/pcm0p/sub0/hw_params
   sleep 0.01 # в чем необходимость такой малой паузы?
done

Где-то так, я не проверял

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 1)
Ответ на: комментарий от sdio

/usr/local/bin/sound.sh: строка 23: ошибка синтаксиса около неожиданной лексемы `done'
/usr/local/bin/sound.sh: строка 23: ` done < /proc/asound/card1/pcm0p/sub0/hw_params'

Andrew ★★★
() автор топика

proc - псевдофс. в данном случае содержимое формируется налету, скорее всего, считыванием какой-либо переменной. так что только поллинг ;)

anonymous
()
Ответ на: комментарий от sdio

Он не гоняет bash.

решать конечно не нам(мы и задачи толком не знаем), но ИМХО оверхед по любому велик.

while read line; .... done </proc/file

не, тут что-то вроде

while true; do
  read </proc/…
  sleep
done
emulek
()
Ответ на: комментарий от Andrew

Работает, но теперь оно ест не 1% CPU, а 12%.

не забудь поставить в начале #!/bin/bash, какая-то другая оболочка может выполнять внешнюю команду [. Для bash это внутренняя команда.

Ну и не забудь «засыпать», вызывая sleep или что-то другое.

И ещё раз, на таких малых интервалах у скриптов очень большой оверхед.

emulek
()
Ответ на: комментарий от emulek

решать конечно не нам(мы и задачи толком не знаем)

Объясню подробнее, может пригодится. Есть USB-звуковушка, если например на нее поступает сигнал частотой 48000Гц, а параметр Clock rate Selector выставлен в 0 (0 - 5, соответственно 6 поддерживаемых частот, 0 — режим 44100), то будут дикие искажения. Вот и нужно, чтобы система меняло значение этого параметра на лету когда нужно.

Andrew ★★★
() автор топика
Ответ на: комментарий от Andrew

раньше жрало меньше, так как работало медленнее. измени паузу на адекватное значение

sdio ★★★★★
()
Ответ на: комментарий от emulek

не забудь поставить в начале #!/bin/bash, какая-то другая оболочка может выполнять внешнюю команду [. Для bash это внутренняя команда.

Стоит.

Ну и не забудь «засыпать», вызывая sleep или что-то другое.

Да, точно. Сейчас снова 1%. Так что погоды от этого изменения в плане потребления ресурсов особо нет, вот потребление памяти возросло с 700кб до 1мб.

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 1)
Ответ на: комментарий от Andrew

вот потребление памяти возросло с 200кб до 1мб.

Ты что-то путаешь, запущенный bash «без ничего» жрет не менее 5Мб

sdio ★★★★★
()
Ответ на: комментарий от Andrew

дык напиши простую утилитку на сишке, там работы на 5 минут. Я-бы сам написал, но эта проблема для меня не актуальна.

emulek
()
Ответ на: комментарий от Andrew

потребление памяти возросло с 700кб до 1мб.

забей. Это мелочи.

emulek
()
Ответ на: комментарий от Zmicier

К сожалению пока не удается сделать патч для alsa-driver, чтобы частота выставлялась автоматически, в зависимости от выводимого потока (как это сделано в WIndows). Также существенным ограничением является фиксирование частоты в dmix - не будешь же постоянно вручную корректировать .asoundrc Поэтому пусть каждый решает для себя, что ему важнее - воспроизведение нескольких потоков одновременно на фиксированной частоте, или возможность менять частоту, и не терять и толики качества материала, но только для одyого потока.

Вот и приходится извращаться.

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 1)
Ответ на: комментарий от Andrew

Однако ваш линукс и говно. Во фряхе можно без проблем играть сколько угодно потоков с любым форматом и частотой дискретизации

anonymous
()
Ответ на: комментарий от Andrew

Я думаю, тебе лучше поставить OSS, это будет даже лучше, чем на фряхе

anonymous
()
Ответ на: комментарий от anonymous

Однако во фряхе моя звуковушка не видится в списке sndstat вообще. Это просто специфика конкретных моделей.

Andrew ★★★
() автор топика
Ответ на: комментарий от sdio

Я смотрю потребление именно скрипта в системном мониторе KDE. Я был неправ в том, что мой скрипт за полчаса потолстел до 964кб и держится стабильно. Ваш скрипт за то же время потолстел до 1192кб. Кроме того, ваш скрипт постоянно выводит "...Ожидается числовое значение".

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 1)
Ответ на: комментарий от anonymous

а ещё твоя фряха позволяет ацп на твоей зк работать одновремнно на разных частотах дискретизации, ага. херню не пиши.

а так и в linux всё работает, для любителей тлз есть монопольный режим без конверсий, и промежуточным вариантом можно выставить максимальную необходимую частоту дискретизации в ~/.asoundrc

anonymous
()

Если 95% времени действия бессмысленны, то и не делай. Скрипт по крону, время рассчитай.

Deleted
()
Ответ на: комментарий от Deleted

Мне расчитывать, когда мне случайным образом захочется послушать трек/посмотреть видео со звуком в частоте отличной от 44100гц? Как ты себе это представляешь?

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 1)
Ответ на: комментарий от Andrew

Повесить на плеер. Запуск/смена трека дергает скрипт парсинга/вывода.

Deleted
()
Ответ на: комментарий от Andrew

купить нормальную звуковую карту? Похоже проблема в том, что твой производитель тупо забил на Linux, и сделал драйвер «для галочки».

emulek
()
Ответ на: комментарий от sdio

в чем необходимость такой малой паузы?

В том, что если пауза больше, то скрипт может не успеть вовремя поменять значение и в начале воспроизведения файла с частотой, отличной от текущей выставленной в Clock rate Selector, будет слышно неприятное искажение.

Andrew ★★★
() автор топика
Ответ на: комментарий от emulek

Сейчас вообще не найдешь звуковушку с официциальной поддержкой линукса. К тому же, эта меня вполне устраивает по своим хар-кам.

Andrew ★★★
() автор топика
Ответ на: комментарий от Andrew

Сейчас вообще не найдешь звуковушку с официциальной поддержкой линукса.

однако полно звуковушек, которые отлично работают без офф поддержки.

emulek
()
Ответ на: комментарий от Andrew

Кроме того, ваш скрипт постоянно выводит "...Ожидается числовое значение".

ты думал я тебе скрипт отлаживать буду?

Твой скрипт полное говно, хотя бы потому что запускает grep, awk и amixer на каждой итерации. Посчитай их ресурсы и узбагойся!

Вот так лучше будет

if [ "$f1" = "rate:" ]; then
         if [ "$RATE" -ne "$f2" ]; then
             RATE="$f2"
             do_it
         fi
fi

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 3)
Ответ на: комментарий от Andrew

будет слышно неприятное искажение.

Поставь 0.1, не помрешь

sdio ★★★★★
()

вот попробуйте эту программу:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>

#define HW_PARAMS_NAME "/proc/asound/card0/pcm0p/sub0/hw_params"

#define MAX_FILE_SIZE 65536

/* 10000 == 10ms */
#define USLEEP_TIME 10000

const char* my_name = NULL;

int read_file(const char* filename, char* buf, int* line_count)
{
	FILE* fs = fopen(filename, "r");
	if(!fs)
	{
		fprintf(stderr, "%s: filename: '%s' %s\n", my_name, filename, strerror(errno));
		return errno;
	}
	int file_size = 0;
	*line_count = 0;
	while(fgets(buf+file_size, MAX_FILE_SIZE-file_size, fs))
	{
		file_size += strlen(buf+file_size)+1;
		assert(file_size<MAX_FILE_SIZE);
		(*line_count)++;
	}
	int err = ferror(fs);
	if(err)
	{
		fprintf(stderr, "%s: filename: '%s' %s\n", my_name, filename, strerror(errno));
		return errno;
	}

	fclose(fs);
	return 0;
}

#define SMATHC "rate: "
int parsing_line(const char* line)
{
	if(strncmp(line, SMATHC, strlen(SMATHC)))
		return 0;
	const char* s = line + strlen(SMATHC);
	int rate = 0;
	while(*s >= '0' && *s <= '9')
	{
		rate *= 10;
		rate += *s++ - '0';
	}
	return rate;
}

int main(int argc, const char* argv[])
{
	my_name = argv[0];
	char* buf = malloc(MAX_FILE_SIZE);
	assert(buf);

	int error_code = 0;
	int old_rate = -1;
	while(!error_code)
	{
		usleep(USLEEP_TIME);
		int line_count = 0;
		error_code = read_file(HW_PARAMS_NAME, buf, &line_count);
		if(!error_code)
		{
			const char* line = buf;
			int rate = 0;
			while(line_count--)
			{
				rate = parsing_line(line);
				if(rate)	break;
				line += strlen(line)+1;
			}
			if(rate)
			{
				if(old_rate<0)
				{
					old_rate = rate;
					//printf("%d\n", rate);
					continue;
				}
				if(old_rate == rate)
					continue;
				printf("%d\n", rate);
				break;
			}
		}
	}
	free(buf);
	return error_code;
}

она выводит rate, если оно изменяется во время работы. Пауза 10мс, менять USLEEP_TIME

Ещё имя файла поменяйте, оно у меня другое.

Код писал неряшливо, и не проверил (у меня почему-то всегда 48000).

Если будут вопросы, пишите.

emulek
()
Ответ на: комментарий от anonymous

без поллинга

эта программа выше, если пауза 10ms, грузит мой говноатом в нетбуке на 2..3%. Я думаю, сегодня будет сложно найти более хреновый процессор, чем у меня. Даже iPentiumIII и то быстрее.

emulek
()
Ответ на: комментарий от emulek

Работает, но если я начну играть файл например в 96000гц, а до запуска программы ничего не играло (файл, если сигнала нет, выводит «closed»), то программа ничего выведет. Соответственно если добавить функциональность по изменению Clock rate Selector и зациклить, то программа в таком случае посчитает что ничего делать не нужно, если я правильно понял.

Andrew ★★★
() автор топика
Последнее исправление: Andrew (всего исправлений: 2)
Ответ на: комментарий от emulek

но аккумуляторы всё такие же как и раньше

anonymous
()
Ответ на: комментарий от Andrew

вот новая функция main() (всё остальное без изменений)

int main(int argc, const char* argv[])
{
	my_name = argv[0];
	char* buf = malloc(MAX_FILE_SIZE);
	assert(buf);

	int error_code = 0;
	int old_rate = -1;
	while(!error_code)
	{
		usleep(USLEEP_TIME);
		int line_count = 0;
		error_code = read_file(HW_PARAMS_NAME, buf, &line_count);
		if(!error_code)
		{
			const char* line = buf;
			int rate = 0;
			while(line_count--)
			{
				rate = parsing_line(line);
				if(rate)	break;
				line += strlen(line)+1;
			}
			if(old_rate<0)
			{
				old_rate = rate;
				//printf("%d\n", rate);
				continue;
			}
			if(old_rate == rate)
				continue;
			if(rate==0)
				continue;
			printf("%d\n", rate);
			break;
		}
	}
	free(buf);
	return error_code;
}

emulek
()
Ответ на: комментарий от anonymous

а ещё твоя фряха позволяет ацп на твоей зк работать одновремнно на разных частотах дискретизации, ага. херню не пиши.

Ты идиот? Там ресемплер на такой случай. А в лялихе костыли

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.