Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Blokujący read i niepełne dane

2 views
Skip to first unread message

heby

unread,
Jul 16, 2020, 10:04:17 AM7/16/20
to
Cześć.

Mam named pipe (mkfifo).

Po jednej stronie ktoś robi 1000000 == ::write (pointer, 1000000);

Po drugiej stronie ktoś robi 1000000 == ::read (pointer, 1000000);

Wszystko działa, dostaje dane.

I przychodzi kernel 5.6.x gdzie "coś naprawiono w rurkach".

https://www.phoronix.com/scan.php?page=news_item&px=Linux-Pipe-Parallel-Job-Opt

I teraz, ku mojemy zdziwieniu, dostaje:

size = ::read (pointer, 1000000);

Gdzie size jest 61578.

Coś podejrzanie blisko rozmiarowi bufora rurki, czyli 64k.

Manula klęczy na kolanach i zapewnia mnie że read w trybie bookującym
nigdy nie wyjdzie z innym size niż kiedy jest fatal lub INTR, ale nawet
wtedy size jest -1. Stackoverflow nieśmiało mu przytakuje.

A tu read wychodzi sobie w połowie czytania zwracając częśc danych ...

O rzesz...

Ja mam buga/zaćmienie czy Torvalds odwalł dziadówę w kernelu?

Bogdan

unread,
Aug 2, 2020, 11:05:33 AM8/2/20
to
W dniu 16.07.2020 o 16:04, heby pisze:
Nikt jeszcze nie odpisał, to może ja się podzielę swoim
przemyśleniem: jeśli "::read" to odpowiednik read(2) (a pytam, bo
brakuje parametru), to jeśli mogłeś zapisać milion bajtów i od razu
odczytać też milion, to masz dość wydajny system lub szczęście, że nic
nie przeszkadzało w trakcie (lub jeszcze jakieś czynniki).
Generalnie, read() powinno umieszczać się w pętli i czytać tyle razy,
aż uzbiera się tyle danych, ile się chciało od początku.
Być może najnowsze zmiany w jądrze po prostu to ujawniły.

--
Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS)
Kurs asemblera x86 (DOS, GNU/Linux): http://bogdro.evai.pl
Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32
www.Xiph.org www.TorProject.org Soft(EN): http://bogdro.evai.pl/soft

heby

unread,
Aug 2, 2020, 11:47:38 AM8/2/20
to
On 02/08/2020 17:05, Bogdan wrote:
> przemyśleniem: jeśli "::read" to odpowiednik read(2) (a pytam, bo
> brakuje parametru),

Tak.

> to jeśli mogłeś zapisać milion bajtów i od razu
> odczytać też milion, to masz dość wydajny system lub szczęście, że nic
> nie przeszkadzało w trakcie (lub jeszcze jakieś czynniki).

Przeszkadze EINTR. Ale to ogarniam.

Do tej pory był albo cały bufor albo nic. Nigdy, na przestrzeni lat, nie
wyleciał assert pilnujący tej liczby albo nie zauważyłem ;). Aż tu nagle ...

> Generalnie, read() powinno umieszczać się w pętli i czytać tyle razy,
> aż uzbiera się tyle danych, ile się chciało od początku.

Tak, poprawiłem to w ten sposób, ale dalej pytanie otwarte: czy to błąd
w kernelu czy raczej naprawiono problem? A może ktoś potafi w BSD
odpowiedzieć? Albo innym sco :)

Queequeg

unread,
Aug 3, 2020, 5:07:26 AM8/3/20
to
heby <he...@poczta.onet.pl> wrote:

> Manula klęczy na kolanach i zapewnia mnie że read w trybie bookującym
> nigdy nie wyjdzie z innym size niż kiedy jest fatal lub INTR,

Pokaż ten fragment.

Zgodnie z moją wiedzą, mając rurkę możesz dostawać dane w jednostkach
PIPE_BUF (linux/limits.h, 4096 bajtów).

https://www.gnu.org/software/libc/manual/html_node/Pipe-Atomicity.html

Reading or writing pipe data is atomic if the size of data written is not
greater than PIPE_BUF. This means that the data transfer seems to be an
instantaneous unit, in that nothing else in the system can observe a state
in which it is partially complete. Atomic I/O may not begin right away (it
may need to wait for buffer space or for data), but once it does begin it
finishes immediately.

Reading or writing a larger amount of data may not be atomic; for example,
output data from other processes sharing the descriptor may be
interspersed. Also, once PIPE_BUF characters have been written, further
writes will block until some characters are read.

https://man7.org/linux/man-pages/man7/pipe.7.html

Tu piszą tylko o nieprzeplataniu danych, ale spodziewałbym się, że dotyczy
to też "granularności" odczytów.

POSIX.1 says that write(2)s of less than PIPE_BUF bytes must be
atomic: the output data is written to the pipe as a contiguous
sequence. Writes of more than PIPE_BUF bytes may be nonatomic: the
kernel may interleave the data with data written by other processes.
POSIX.1 requires PIPE_BUF to be at least 512 bytes. (On Linux,
PIPE_BUF is 4096 bytes.) The precise semantics depend on whether the
file descriptor is nonblocking (O_NONBLOCK), whether there are
multiple writers to the pipe, and on n, the number of bytes to be
written:

--
Pewna położna została zwolniona z pracy. Bawiła się na porodówce
telefonem i miała 20 nieodebranych.

heby

unread,
Aug 4, 2020, 5:35:50 AM8/4/20
to
On 03/08/2020 11:07, Queequeg wrote:
>> Manula klęczy na kolanach i zapewnia mnie że read w trybie bookującym
>> nigdy nie wyjdzie z innym size niż kiedy jest fatal lub INTR,
> Pokaż ten fragment.

Fragment jest komercyjny wiec nie pokażę. Ale sprowadza się do:

size = read( ..., _size, ... )
...
assert( size == _size );

Ten assert nigdy nie wyskakiwał aż do nowego kernela.

> Zgodnie z moją wiedzą, mając rurkę możesz dostawać dane w jednostkach
> PIPE_BUF (linux/limits.h, 4096 bajtów).

No wiec na nowym kernelu dostaje np. 6xxxx bajtów, czasami całość.

Na starym zawsze całość.

Można to lepiej zaobserwować jest jest 1 read ale 2x write do tej samej
rurki. Wczesniej oba "write" były atomowe, obecnie dostaje troche danych
z pierwszego write a troche z drugiego i wyglada na to że zależy to od
shedulowania procesów/threadów bo jest randomiczne i zalezy silnie od
obciązenia cpu.

Queequeg

unread,
Aug 4, 2020, 6:07:04 AM8/4/20
to
heby <he...@poczta.onet.pl> wrote:

> No wiec na nowym kernelu dostaje np. 6xxxx bajtów, czasami całość.
>
> Na starym zawsze całość.

Mówiłeś, że 61578. Dziwna wartość, bo niepodzielna przez 4096.

Może na starym kernelu działało przez przypadek, bo implementacja w
kernelu była inna.

> Można to lepiej zaobserwować jest jest 1 read ale 2x write do tej samej
> rurki. Wczesniej oba "write" były atomowe, obecnie dostaje troche danych
> z pierwszego write a troche z drugiego i wyglada na to że zależy to od
> shedulowania procesów/threadów bo jest randomiczne i zalezy silnie od
> obciązenia cpu.

Po sieci to normalne. Generalnie pracując ze strumieniami trzeba się
spodziewać, że najmniejszą jednostką podziału jest bajt.

Zastanawiam się tylko, na ile ta granularność jest zmieniana, jeśli nadal
używamy protokołu strumieniowego, ale nie po sieci, a lokalnie po rurkach.
Spodziewałbym się, że granularność będzie na poziomie PIPE_BUF, czyli
paczki po 4096 bajtów, ale... może jednak nie?

--
Wpada zajączek do lisiej nory i pyta:
- Jest ojciec?
- nie ma..
- Jest matka?
- nie ma..
- A chcecie w te rude ryje?!

heby

unread,
Aug 4, 2020, 1:20:13 PM8/4/20
to
On 04/08/2020 12:07, Queequeg wrote:
>> No wiec na nowym kernelu dostaje np. 6xxxx bajtów, czasami całość.
>> Na starym zawsze całość.
> Mówiłeś, że 61578.

To tylko jedna z wartości.

> Dziwna wartość, bo niepodzielna przez 4096.

Ale bliska 64k.

https://linux.die.net/man/7/pipe

[...]Since Linux 2.6.11, the pipe capacity is 65536 bytes. [...]

> Może na starym kernelu działało przez przypadek, bo implementacja w
> kernelu była inna.

Tak też zakładam. ALE. Obejrzałem trochę kodu z róznych opensource.
*Raczej* nikt nie zakłada że przyjdzie połowa danych. Co oznacza że albo
wszyscy popełniają ten sam błąd, albo jednak blokujący read zwracający
połowę zeklarowanej ilości to coś nowego.

> Po sieci to normalne. Generalnie pracując ze strumieniami trzeba się
> spodziewać, że najmniejszą jednostką podziału jest bajt.

Gwarantowali atomowość do PIPE_BUF. W praktyce działało to na większych.

Queequeg

unread,
Aug 4, 2020, 3:54:48 PM8/4/20
to
heby <he...@poczta.onet.pl> wrote:

>> Dziwna wartość, bo niepodzielna przez 4096.
>
> Ale bliska 64k.
>
> https://linux.die.net/man/7/pipe
>
> [...]Since Linux 2.6.11, the pipe capacity is 65536 bytes. [...]

No proszę, zwiększyli.

> Tak też zakładam. ALE. Obejrzałem trochę kodu z róznych opensource.
> *Raczej* nikt nie zakłada że przyjdzie połowa danych. Co oznacza że albo
> wszyscy popełniają ten sam błąd, albo jednak blokujący read zwracający
> połowę zeklarowanej ilości to coś nowego.

Hmm. Ja zawsze zakładam. Widziałem za to kod, który nie zakładał, i
musiałem go poprawiać, bo się czasem, niedeterministycznie, wysypywał.

>> Po sieci to normalne. Generalnie pracując ze strumieniami trzeba się
>> spodziewać, że najmniejszą jednostką podziału jest bajt.
>
> Gwarantowali atomowość do PIPE_BUF. W praktyce działało to na większych.

Pytanie czy do PIPE_BUF, czy do dowolnej wielokrotności PIPE_BUF...

--
Rozmawia dziennikarz ze znanym rabusiem:
- Jakie jest pana najwieksze marzenie?
- Obrobic bank i zostawic odciski palcow tesciowej...
0 new messages