rockowitz / ddcutil

Control monitor settings using DDC/CI and USB
http://www.ddcutil.com
GNU General Public License v2.0
981 stars 41 forks source link

Maximum speed configuration? #110

Open JakubFojtik opened 4 years ago

JakubFojtik commented 4 years ago

What arguments would cause the maximum execution speed of the setvcp command run one after another?

I am using --noverify --sleep-multiplier 0.1, but the command sometimes needs retrying due to the low multiplier.

Are there other ways to increase speed, like opening a "socket" and reusing it?

I wanted to match the speed of the proprietary I-Menu for AOC monitors, where one can change brightness via a slider real-time. Is that posible with ddcutil's I2C, or are they using their own proprietary protocols?

rockowitz commented 4 years ago

On 3/7/20 2:19 PM, JakubFojtik wrote:

What arguments would cause the maximum execution speed of the |setvcp| command run one after another?

I am using |--noverify --sleep-multiplier 0.1|, but noverify seems to do nothing and the command sometimes needs retrying due to the low multiplier.

Are there other ways to increase speed, like opening a "socket" and reusing it?

The execution time of ddcutil is dominated by sleeps mandated by the DDC/CI protocol. (--sleep-multiplier, as you know, allows you to adjust the length of those sleeps to a lower value that still works for your monitor.)  The time spent opening and closing /dev/i2c devices is negligible - see the output of the --stats option.

The current version of branch 0.9.9-dev on github contains a change which eliminates some sleeps entirely and does not appear to cause problems.

You could also run ddcutil using the --bus option, which bypasses display detection, though this is of most value in a multi-monitor environment.

Do be aware that some users have reported problems when multiple setvcp commands issued in rapid succession, i.e. in a script.

I wanted to match the speed of the proprietary I-Menu for AOC monitors, where one can change brightness via a slider real-time. Is that posible with /ddcutil/'s I2C, or are they using their own proprietary protocols?

I-Menu is proprietary Windows software.  I have no idea what they're doing.

If you're looking to adjust brightness using a slider, take a look at ddcui.  Just beware that what's on github is very much a beta release.

-- Sanford

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/rockowitz/ddcutil/issues/110?email_source=notifications&email_token=ADMGY3QIIEWG7DTCCBRAVRTRGKM3VA5CNFSM4LDSIYT2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4ITKHMDQ, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADMGY3SV7I43HUBFG2GR2O3RGKM3VANCNFSM4LDSIYTQ.

ashutoshgngwr commented 1 year ago

AFAIK, MonitorControl also uses the DDC protocol to do this in real-time on MacOS. Its brightness sliders are smooth. Perhaps it might help.

Cimbali commented 1 year ago

I’ve had similar smooth experience on Windows, with Twinkle Tray which seems to use node-ddcci as a library to call low level windows API functions such as SetVCPFeature.

Note that I’m sure a 100ms delay is barely noticeable in a slider unless you’re looking for it. But currently with ddcutil 2.0 I see things like:

> time ddcutil -b 1 setvcp 10 100

real    0m3.007s
user    0m0.010s
sys     0m0.067s

So 10ms of user time, 67ms of kernel time, but 3 full seconds of wall clock time -- specifying the bus directly. Not on all monitors thankfully, but even on a faster one there’s at least a lot of variability:

> time ddcutil -b 10 setvcp 10 100

real    0m0.547s
user    0m0.006s
sys     0m0.013s
> time ddcutil -b 10 setvcp 10 100

real    0m0.401s
user    0m0.012s
sys     0m0.006s
> time ddcutil -b 10 setvcp 10 100

real    0m0.167s
user    0m0.008s
sys     0m0.009s

The only other linux implementation I found is based on i2c-tools, e.g. python-ddci. That seems to be more error-prone as on the bus that performs slower with ddcutil the ddcli command returns without actually modifying the brightness 3 out of 4 times. (ddcutil also fails but much less frequently with “VCP (aka MCCS) version for display is undetected or less than 2.0. Interpretation may not be accurate. Verification failed for feature 10“). Besides it being less reliable, it is blazingly fast:

> time ./ddccli.py -b 1 --brightness 10

real    0m0.028s
user    0m0.019s
sys     0m0.009s

> time ./ddccli.py -b 1 --brightness 100

real    0m0.030s
user    0m0.017s
sys     0m0.013s

> time ./ddccli.py -b 10 --brightness 10

real    0m0.031s
user    0m0.021s
sys     0m0.006s

> time ./ddccli.py -b 10 --brightness 100

real    0m0.038s
user    0m0.027s
sys     0m0.007s

So it’s likely the python-ddci/i2c-tools is skipping a lot of possibly mandatory things, but maybe there could be some inspiration taken from there to make things faster?

rockowitz commented 1 year ago

@Cimbali Is this performance problem new with release 2.0? If so, it might be related to the newly introduced dynamic sleep algorithm, and that needs to be diagnosed.

Before doing anything else, make a copy of $HOME/.cache/ddcutil/dsa so that your accumulated data is not affected by subsequent tests. Next please run sudo ddcutil interrogate and save the output. The output is voluminous, but it avoids a back and forth over lots of little questions. Submit both files as attachments of some sort.

Options --stats and --vstats provide lots of detail about where ddcutil is spending its time and how many I2C retries are required. The latter breaks down the stats by monitor. (If the issue is in the new dynamic sleep algorithm, option --istats dumps internal information as well.)

My guess is that the DDC implementation for the display on bus 1 is marginal, and that the stats will show lots of retries. Assuming the runs on bus 10 are sequential, the decreasing elapsed time would reflect the tuning as dynamic sleep reduces the sleep multiplier.

Try running with option --disable-dynamic-sleep and use option --sleep-multiplier to explicitly set the multiplier factor to be used. Can you find a sleep multiplier value that improves performance? If so, there may be a problem with the dynamic sleep algorithm.

Yes, ddcutil does a lot of checking that python -ddci does not, so it probably works more reliably with your marginal monitor, at the expense of performance. In particular, setvcp automatically performs a getvcp operation to verify that the monitor's value has changed. python-ddcci does not appear to perform that check. Running ddcutil with option --noverify would make its performance more comparable to python-ddcci.

i2c-tools is basically a thin application over driver i2c-dev. ddcutil makes essentially the same system calls to i2c-dev as does i2c-tools.

Regarding Windows, the API functions such as SetVCPFeature are at a much higher level than the I2C interface provided by i2c-dev. If ddcutil were ported to Windows the lowest layers of ddcutil would simply be stripped out. Plus, the Windows video drivers simply have better I2C support. I'm not surprised that DDC performance is better on Windows.

Cimbali commented 1 year ago

It’s not new with 2.0, it was already there before -- I was just hoping 2.0 would fix it.

I have an applet to control monitor brightness and was hoping to use DDC rather than xrandr --brightness. In that use case (by scrolling or with a slider), a very large response time is not ideal (3s is not usable, but I’m sure some people could tolerate up to 0.5s).

I understand your new sleep algorithm is dynamically reducing or increasing the sleep multiplier based on previous calls. Is there a way to profile that value? Say on detecting a new screen is connected, run a dozen dummy commands (or brightness -1% / +1%), or until the value has converged?

rockowitz commented 1 year ago

I agree that 3.0s execution time for individual ddcutil calls makes it unusable for a scrollbar in an app. The real solution is to use the shared library which performs initialization once, but I appreciate that until libddcutil has a python interface that is impractical for most developers. You might want to take a look at how vdu_controls gets around this problem.

Tuning the dynamic sleep-multiplier requires a large number of calls. Doing this automatically when a new monitor is detected would make the initial ddcutil call so slow that it would be perceived as failing. However, your app could have an option to perform a long running profile operation by making a large number of getvcp calls (and hiding the output) on user request.

rockowitz commented 1 year ago

@Cimbali, I have added an experimental option to branch 2.0.2-dev, -skip-ddc-checks. It is valid only if the display is selected by its bus number (option --bus) and only for commands getvcp and setvcp. Because it is experimental, it is listed only by option --hh, not --help.

If specified, ddcutil initialization does not check if DDC communication is working, and does not check that the monitor reports unsupported features as per the DDC/CI spec, For any "reasonable" monitor, these checks should never fail. The downside is that either of these things is not true, it's unclear how the getvcp or setvcp command will fail.

Also, to make the slider more responsive and if you have not already done so, consider using option --noverify on the setvcp calls, and only call getvcp once after the slider operation is complete to get the final value.