46

Dave Cutler is well known for his contributions to operating systems, having led the effort on VAX VMS at DEC and Windows NT at Microsoft. According to his Wikipedia page, he is also known for his attitudes toward Unix.

[Cutler] expressed his low opinion of the Unix process input/output model by reciting "Get a byte, get a byte, get a byte byte byte" to the tune of the finale of Rossini's William Tell Overture.

While I am sure that the merits of Cutler's stated "low opinion" could be debated, I'm interested to better understand exactly what he was referring to here. There isn't any citation, and I haven't found a good explanation critiquing his criticism.

What specific or fundamental difference between Unix and VMS or Windows NT (which borrowed heavily from VMS) was Cutler pillorying?

2
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Chenmunka
    Mar 21, 2020 at 10:55
  • 12
    There's a vote-to-close pending on this. I think it's a valid question (and I'm not just saying that because I've got the accepted answer). While the wording of the question may itself be borderline, it has surfaced discussion about certain historical differences in system philosophy that I find interesting. "Retrocomputing" is not just a matter of old hardware; old software is IMO as interesting. I'm posting this as a comment since AFAIK there is no "vote to not close" (which seems like an omission in the democratic process) Mar 21, 2020 at 23:53

6 Answers 6

65

The I/O model on "Cutler systems" – RSX-11M, VAX/VMS, Windows NT – is an asynchronous packet-driven I/O model, rather than the fundamentally synchronous I/O model of Unix. At its core, you fire off an I/O request, and get a notification of when it's complete. Meanwhile, execution continues.

Of course, it's trivial for the system to provide synchronous I/O routines on top of that: have the I/O request completion set a condition ('event flag') and then wait on that condition.

In contrast, adding asynchrony on top of a synchronous I/O system is rather more involved.

This, I think, is the nub of Cutler's argument against Unix I/O.

I can provide no citation, however, and I am also biased towards packet-driven I/O, so maybe it's just one (more) man's opinion.

(No implication intended that packet I/O was a Cutler invention – it was certainly present in prior systems, and it was required to implement I/O that way in RSX-11M for compatibility.)

14
  • 3
    At low level, I've used it on Windows where it's pretty OK and on high level there's C#/Javascript/Typescript with their excellent async/await. A few years ago I wanted to write a small Linux program in C that would asynchronously read from two HDDs at the same time and found it to be a harder task than I anticipated. I didn't spend much time on it though and abandoned the effort - maybe I just didn't find the right approach.
    – Vilx-
    Mar 18, 2020 at 12:33
  • 4
    @poncho: No, not really. All I/O operations still block a thread, it's just that the keyboard/screen I/O no longer get blocked by the disk/network I/O if they're on different threads.
    – MSalters
    Mar 19, 2020 at 12:28
  • 3
    @poncho: True. But that can be very expensive
    – MSalters
    Mar 19, 2020 at 15:10
  • 4
    @MSalters Generally speaking, threads and processes are cheap in Linux (with the caveat you use a smaller initial stack size) but comparatively more expensive on VMS and Windows - so I imagine that makes-up for the difficulty of doing true async IO.
    – Dai
    Mar 19, 2020 at 21:53
  • 4
    @Dai Except that one of the costs of that is the massive memory overcommit that Unix systems are plagued with. Every piece of server software on Unix must be ready to be rudely killed at any time and restarted again. The only way to avoid this is to do manual memory management on pretty much everything. And yet, even despite the "cheap" processes on Unix, server software uses asynchronous IO.
    – Luaan
    Mar 20, 2020 at 9:49
23

While I am sure that the merits of Cutler's stated "low opinion" could be debated, I'm interested to better understand exactly what he was referring to here. There's no citation, and I haven't found a good explanation critiquing his criticism.

Honestly, at face value, it's a naive criticism. Cutler was not naive, so, it's likely just a sound bite poke at UNIXs development model.

But that said, when you look at the larger picture, notably the "tools" notion of UNIX (as expressed in books such as Software Tools by Kernighan and Plauger) they demonstrate writing code and using things such as getc or getchar along with putc and putchar. The simplistic interface of reading from standard input, processing it, and writing to standard output. It's the essence of the composability of software that "does one thing and does it well".

These are, indeed, "get a byte, put a byte", and are well known to have a higher over head than block reads and writes. If you want I/O to perform well, it's best done in device size blocks (e.g. 1K, or 4K, depends on the device).

Now, in reality, underneath those getc calls are block I/O calls. Underlying code loads up a buffer, and then works through that buffer, refilling as necessary.

There is higher function overhead, but not necessarily I/O overhead.

Perhaps these were naively implemented back in the day (I doubt it).

There is/was nothing stopping UNIX processes from doing more efficient block I/O, but idiomatically, it was not presented that way.

VMS is in many ways the antithesis of UNIX, with its special file formats and dedicated utilities in contrast to the UNIX universal stream of bytes and composable tools model.

15
  • 2
    Note that 'file formats' were done in a layer above base I/O, though that was not immediately obvious to user-mode programmers. Come to that, files were a layer above drivers, too - in RSX and early VMS, implemented in a single system process ('ACP') by diverting I/O requests from the kernel. Mar 17, 2020 at 17:30
  • 7
    @another-dave of course they were, but that doesn't change their presentation as first class objects to users of the system. "All" of the basic utilities on a UNIX system view files (and, mostly, everything else) as streams of bytes. The highest level abstraction available is the idea of the "line" (delimited by newline), but "cat", for example, would dump a text file, a serial port, a database index, etc. VMS basic utitlities did not publish that low level view of the data, but subscribed to the higher level formats supported by the system. Mar 17, 2020 at 19:57
  • 7
    @WillHartung ... presumably leaving you stranded once you start debugging "I don't have the tool to read this type of data source". Vendor: "That's USD 10'000 for a site-wide licence, thank you." Mar 18, 2020 at 11:59
  • 2
    @Luaan It's not harder, but it's more fragile. You tend to end up various creeks without paddles. Briefly, you don't want interpretation at the OS/FS level - you want it at the application level. A bunch of undocumented bytes becomes documented immediately by virtue of XML schema or an RFC for example. Want to read ASN.1 from several places? Use a library, don't add a specific ASN.1 data stream to the system. In fact, don't bury fragile and hard-to-maintain semantics deep into the system. Generality! Eric Raymond explains Mar 20, 2020 at 10:18
  • 2
    @Luaan It comes system-wide. But only on THIS SYSTEM, possibly on THIS VERSION OF THE SYSTEM (specific to "medical organizations" as your vendor will helpfully explain). You don't need to update all your applications at all unless you have compiled everythign statically (who does that anymore). Just upgrade the library. In any case, you still need to have full access to the bytestream, otherwise such things as SQLite could not exist, or only exist in vendor-specified straightjackets. Why have that? Download the reader/writer library! Which you can debug.This is such a discussion from the 80s. Mar 20, 2020 at 11:18
23

At the operating system level – as seen by applications – files in VMS are very record oriented. Guide to OpenVMS File Applications (336 page, 2MB PDF) probably goes into far more detail than anyone should be expected to know, but you can get a feel from the Introduction (emphasis mine):

1.1 File Concepts

A computer file is an organized collection of data stored on a mass storage volume and processed by a central processing unit (CPU). Data files are organized to accommodate the processing of data within the file by an application program. The basic unit of electronic data processing is the record. A record is a collection of related data that the application program processes as a functional entity. For example, all the information about an employee, such as name, street address, city, and state, constitutes a personnel record. Records are made up of fields, which are sets of contiguous bytes. For example, a person’s name or address might be a field. A byte is a group of binary digits (bits) that are used to represent a single character. You can also think of a field or an item as a group of bytes in a record that are related in some way.

VMS normally imposes a very database-like view on files at the operating-system level. In contrast, to Unix a file is just "a bag of bytes" and any higher-level organisation is imposed on it by the application program.

It is possible to create VMS files that are little more than "bags of bytes" (using the "stream" record-format), and – from my experience several years ago – doing so is pretty much mandatory if you want to port a "typical Unix program" to VMS... trying to do byte-by-byte file operations on a file organised (by the operating system) as fixed-length records was a recipe for problems.

VMS's record-level view of files goes quite a lot further than "just" reading/writing in fixed-sized chunks and includes built-in handling of record-locking, indexing, control over how files grow and a whole lot more (over 300+ pages more!) that I never had to get into.

Although I cannot be certain, I strongly suspect it is the lack of this OS-level support for "organised data" files that Dave Cutler was complaining about.

2
  • That's at RMS level, which is above file systems, which is above drivers. The way I'd heard it at DEC, Cutler was not particularly interested in the RMS level and might even have argued against putting in the OS. But I can't substantiate any of that :-( Mar 18, 2020 at 22:25
  • 1
    … assuming that M. Cutler ever said such a thing at all. The closest that I have found is an anecdote told by Armando Stettner where M. Cutler is recorded as disparaging Armando Stettner and Bill Shannon as "sorry excuses for engineers". There was some SRI software involved, my guess being Eunice. But nothing is recorded there of M. Cutler's views on Eunice, let alone on UNIX. The person who put this stuff into Wikipedia that people are taking at face value also made edits relating to M. Stettner.
    – JdeBP
    Mar 19, 2020 at 11:26
10

At that time, computing model was very rich API, complex CPUs, complex tools, etc. Filesystem were almost structured files oriented, etc. UNIX came with its "uniform" vision of I/O, everything is a file, a file is just a stream of bytes. That wasn't so easy for people trained on former OSes to understand why UNIX is a good model. While I loosely remember the debate over OSes (I used many of them so I saw how people debated on this), I can remember the same debate over CISC/RISC architectures. The same for compiler, there was a time were people thought that compiler as to be simple translator of very rich programming languages, but now it is more the converse and nobody would try to beat a compiler writing assembler by hand. For I/O I remember all those system engineers and developers which were semi-gods at choosing the right setting to obtain a very tricky effect... I think there is nothing very profound in Cutler's remark, two worlds were in "fight", that's all, and the one that wins in the end is not Cutler's one and he probably knew it).

1
  • 2
    But this is also a part of the commodization of the working area. Which also unfortunately means that we get errors and faults of other types than yesterday ! I looked for a work as a system operator 1988 (IBM es - 390.) At that time if the operator ran a job in the wrong order the line printer started to empty a cartoon of paper FAST ! 4 printers who do that at the same time is impressive in the way how heavy that waste paper soon is ! Mar 18, 2020 at 14:56
8

Having never written Unix I/O code beyond munging text files, read what follows with a grain of salt.

In uni we were a VMS shop. I still recall when the VAX 11/780 in the walled-off computer room was replaced by a single DECStation 3100 on a desk. That machine ran both OSes and we (the OS course's 12-or-so members) began to compare and contrast the approaches while writing our own OS as our 4th year project.

The prof noted that Unix's I/O model relied on the underlying OS to efficiently context switch (which it did), so this was the basis for entire software stack. Even at the application level, the assumption was just "ask for the precise bit of data you want" and it would magically appear. That you might have blocked while it arrived was both invisible and unavoidable.

That model worked well in memory-limited systems, like the PDP-11/20 with a maximum of 32kwords. In this case you had limited space to play with buffers, and I/O was simple and blocking anyway due to the nature of the bus. So to actually transfer that data you needed to context switch anyway, so just do that, bake it into the entier system. In this respect, Unix may be considered well-tuned for minicomputer systems of the era.

But the same is not true for mainframes, which invariably featured some level of autonomous DMA and dedicated buffers. The data is likely arriving rapidly in larger chunks, say 2k HD blocks which magically appear all at once. In this case, the proper model is to process as much of that data as you can before forcing another context switch, because reading one line of text from a 2k buffer and then waiting for the next switch is helping no one.

I vaguely recall a text file floating around usenet comparing the two approaches for a simple text munger running under VMS and Unix on the same machine (a 11/780 IIRC). Even for very simple tasks like those of the unix "tools" pattern, both the application itself and the overall OS performance (total throughput of all running apps) was significantly higher under VMS. Almost all of this was because of avoided switches. I'll see if I can dig it up.

3
  • I agree, though I have to giggle at the implication that an 11/780 is anywhere close to being a "mainframe". In an earlier life I made VAXen talk to IBM mainframes.... Mar 23, 2020 at 19:29
  • But how much of this is simply idiomatic in how programs were made, vs limitiations of the underlying system? UNIX certainly supported Async block I/O within the kernel. When it was exposed to system programmers, I can't say. I'd bet earlier than later. It's not surprising that Async block I/O processing is faster than character I/O, but doesn't necessarily mean that it couldn't be done on a userland program in UNIX. Mar 24, 2020 at 14:36
  • @WillHartung - probably all of it! Mar 24, 2020 at 20:02
5

Solely based on the source link to Dave's comment, I can't really tell what he meant.

That said, Benno Rice recently gave an excellent talk at linux.conf.au called What UNIX Cost Us.

The TL,DR of that talk is that many of UNIX's core assumptions, though extensible, no longer apply in current and next gen environments, which makes supporting new paradigms with them extremely difficult.

As an example of this, consider services management. Windows has Services.msc, which was designed to be easy enough for your average high school grad to understand and use. Systemd is a step in that direction for Linux, but is reviled by many for UNIX "nonconformance." Then you have OSes like FreeBSD that supposedly do things the UNIX way, but init is so clunky even FreeBSD's own documentation suggests simply using cron jobs with @reboot instead:

In some cases, it may make more sense to use cron(8) to start system services. This approach has a number of advantages as cron(8) runs these processes as the owner of the crontab(5). This allows regular users to start and maintain their own applications.

The @reboot feature of cron(8), may be used in place of the time specification. This causes the job to run when cron(8) is started, normally during system initialization.

9
  • 3
    Console I/O is perhaps one of the most obvious places the Unix design was costly. Many applications functions to "read a line of up to N characters from the console" or "read one raw byte from the console". The Unix approach to buffering may improve performance on memory-limited time-sharing systems, but except when bypassed in "raw mode" it really doesn't fit well with either of the common paradigms.
    – supercat
    Mar 18, 2020 at 23:48
  • 4
    rc.d is a directory name on FreeBSD, not a dæmon.
    – JdeBP
    Mar 19, 2020 at 11:05
  • 4
    rc is not a daemon either -- it's just a shell script run once at boot. init is the daemon that runs it. The rc(1) manual page does not suggest using cron instead either (nor can I find this in the Handbook), and the reasons any other documentation might recommend doing so are far more subtle than you suggest. Mar 21, 2020 at 17:35
  • 1
    That's a wild misreading of the doco in front of you. The suggestion is to use cron for single-shot stuff and stuff where non-administrators might want to set up stuff. This not commentary on Mewburn rc. All of these mistakes and the fact that you've erroneously conflated init and rc (asserting the former to be "clunky" based upon things that it isn't even involved in) tell people that this answer is not a well-informed critique. Moreover: The recommendation to use cron is repeated frequently on Unix and Linux Stack Exchange, often by/to people using Linux, indeed.
    – JdeBP
    Mar 24, 2020 at 11:18
  • 1
    @JdeBP My own experience with setting up services in FreeBSD, systemd Linux, and Windows tells me that UX and ease of working with the system increases in that order 🤷‍♂️. In fact, I'd call systemd Linux the floor of usability for me. Whatever service management exists, I don't want it being more complicated or involved to manage than that.
    – jdrch
    Mar 24, 2020 at 19:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .