Hacker Newsnew | past | comments | ask | show | jobs | submit | database64128's commentslogin

> Every time I login using a Wayland desktop, only my main monitor is detected and it defaults to 60hz. I have to go through a whole process of unplugging the "undetected" monitors and plugging them back in.

Are you using GNOME? mutter has this problem where it does not retry commit on the next CRTC: https://gitlab.gnome.org/GNOME/mutter/-/issues/3833. If this is actually what's happening on your system, switching to KDE should solve it.

> HDR on Wayland is barely functional (in my experience)

This also sounds specific to GNOME, as mutter still doesn't have color management. You'll get a better HDR experience with KDE.


GNOME is typically the worst of all the options if you need feature support. They aggressively nack wayland proposals, and subsequently don't implement those proposals - while almost the entirety of the ecosystem does.


Seriously, it's bizarre to me how aggressively they pushed to use Wayland but then hold it back like that.


> This also sounds specific to GNOME, as mutter still doesn't have color management.

Gnome 49 should've solved that. [0]

[0] https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4102


I don't think so. I'm on GNOME 49 and nothing has changed compared to 48.


GNOME has both color management and color representation protocols implemented. HDR works fine on it


No, having the bare minimum "HDR support" does not mean it works fine. I have a 27-inch 4K 144Hz monitor with P3 wide color gamut and HDR600. This monitor is connected to 2 PCs, one running Arch Linux with GNOME as the DE and one with Windows 11.

Since Windows 11 24H2, with the new color management feature turned on, I can get correct colors on the monitor in both SDR and HDR modes. So it ends up with HDR on at all times, and mpv can play HDR videos with no color or brightness issues.

GNOME, on the other hand, is stuck with sRGB output in SDR mode, so you get oversaturated colors. With HDR on, SDR content will no longer be oversaturated, but if you play HDR videos with mpv, the image looks darkened and wrong. I've tried setting target-peak and target-contrast to match the auto-detected values on Windows, but the video still looks off.


Sorry it doesn't work for you. I don't have that issue. Gnome looks proper in HDR mode for both HDR and SDR content for me.


Yes. To land a change in the Go standard library, you'll need 2 Google employees to approve your change on their "trusted devices".


This is demonstrably false. There are many approvers that do not work for Google.


Have you actually contributed to the Go standard library?

Yes, there are people who don't work for Google and can +2 on changes, but you still need 2 Google employees to at least +1 on your change before it can be submitted. This is mentioned in the Contribution Guide [0] and is enforced by Gerrit.

> Finally, to be submitted, a change must have the involvement of two Google employees, either as the uploader of the change or as a reviewer voting at least Code-Review +1. This requirement is for compliance and supply chain security reasons.

[0] https://go.dev/doc/contribute


When someone says demonstrably, I expect they would follow up with said demonstration


Then it should be easy to find examples of changes going into the STL that have not had the approval of multiple Googlers.


I see you use a hard-coded constant ALIGN = 512. Many NVMe drives actually allow you to raise the logical block size to 4096 by re-formatting (nvme-format(1)) the drive.


I realise this and also implemented it properly here before: https://github.com/steelcake/io2/blob/fd8b3d13621256a25637e3...

Just opted to use fixed 512 byte alignment in this library since all decent SSDs I have encountered so far are ok with 512 byte file alignment and 64 byte memory alignment.

This makes the code a bit simpler both in terms of the allocator and the file operations.


It’s really the hardware block size that matters in this case (direct I/O). That value is a property of the hardware and can’t be changed.

In some situations, the “logical” block size can differ. For example, buffered writes use the page cache, which operates in PAGE_SIZE blocks (usually 4K). Or your RAID stripe size might be misconfigured, stuff like that. Otherwise they should be equal for best outcomes.

In general, we want it to be as small as possible!


> It’s really the hardware block size that matters in this case (direct I/O). That value is a property of the hardware and can’t be changed.

NVMe drives have at least three "hardware block sizes". There's the LBA size that determines what size IO transfers the OS must exchange with the drive, and that can be re-configured on some drives, usually 512B and 4kB are the options. There's the underlying page size of the NAND flash, which is more or less the granularity of individual read and write operations, and is usually something like 16kB or more. There's the underlying erase block size of the NAND flash that comes into play when overwriting data or doing wear leveling, and is usually several MB. There's the granularity of the SSD controller's Flash Translation Layer, which determines the smallest size write the SSD can handle without doing a read-modify-write cycle, usually 4kB regardless of the LBA format selected, but on some special-purpose drives can be 32kB or more.

And then there's an assortment of hints the drive can provide to the OS about preferred granularity and alignment for best performance, or requirements for atomic operations. These values will generally be a consequence of the the above values, and possibly also influenced by the stripe and parity choices the SSD vendor made.


I've run into (specialized) flash hardware with 512 kB for that 3rd size.


Why would you want the block size to be as small as possible? You will only benefit from that for very small files, hence the sweet spot is somewhere between "as small as possible" and "small multiple of the hardware block size".

If you have bigger files, then having bigger blocks means less fixed overhead from syscalls and NVMe/SATA requests.

If your native device block size is 4KiB, and you fetch 512 byte blocks, you need storage side RAM to hold smaller blocks and you have to address each block independently. Meanwhile if you are bigger than the device block size you end up with fewer requests and syscalls. If it turns out that the requested block size is too large for the device, then the OS can split your large request into smaller device appropriate requests to the storage device, since the OS knows the hardware characteristics.

The most difficult to optimize case is the one where you issue many parallel requests to the storage device using asynchronous file IO for latency hiding. In that case, knowing the device's exact block size is important, because you are IOPs bottlenecked and a block size that is closer to what the device supports natively will mean fewer IOPs per request.


You could use something like https://github.com/database64128/swgp-go to obfuscate WireGuard traffic.

Using full-blown VPNs under such environments has the disadvantage of affecting your use of domestic web services. You might want to try something like https://github.com/database64128/shadowsocks-go, which allows you to route traffic based on domain and IP geolocation rules.


> One problem with Go is the lack of fine-grained control over allocation. In particular, no arena allocation support. How does C# compare?

Go has an experimental arena package [0], but the proposal is on hold and the code may be removed in the future.

C# does not support arenas. But it does provide the stackalloc keyword, whereas in Go you kind of need the compiler's blessing for avoiding heap allocations.

> Another problem is relatively high cost of FFI interop with C. It's gotten better, but Go still needs to switch stacks, etc. How is C#?

Async in C# is implemented as stackless coroutines. Calling into FFI is cheap.

> How does C# compilation speed compare?

In my experience, release builds are a bit slower than Go.

> Does the compiler optimize more aggressively than Go (which does very little optimization)? I've heard the C# AOT compiler is lacking, but it's not clear in what way.

Not much to say on this, but with each new .NET release, a core .NET team member posts a blog post about performance improvements in the new release. The most recent one: https://devblogs.microsoft.com/dotnet/performance-improvemen...

> Does C# have the equivalent of "go run"?

  dotnet run
> What's the package management situation like?

NuGet Gallery [1] is like a centralized DLL registry. Definitely not as good as Go.

> Can you use LINQ against databases like Postgres on Linux, without having to buy into a lot of Microsoft/.NET stuff?

Probably not. This is usually done with EF Core and the Postgres provider.

[0] https://github.com/golang/go/issues/51317

[1] https://www.nuget.org/


>> Can you use LINQ against databases like Postgres on Linux, without having to buy into a lot of Microsoft/.NET stuff?

>Probably not. This is usually done with EF Core and the Postgres provider.

You can use Npgsql[0] alone or with non-EF Core interfaces, since it's just a ADO.NET Data Provider (for others: the common interface for database access in dotnet).

The GP question is interesting because it asks about using LINQ with databases "without having to buy into a lot of Microsoft/.NET stuff". I'm going to assume they mean "without using all-microsoft-sourced libraries and frameworks like Entity Framework" (since LINQ is a .NET library interface thing anways).

A couple of example of alternatives that support utilizing Npgsql for database access:

1. Linq2DB: https://linq2db.github.io

2. Dapper: https://github.com/DapperLib/Dapper?tab=readme-ov-file#will-...

3. SqlHydra: https://github.com/JordanMarr/SqlHydra?tab=readme-ov-file#co...

There are a number of other libraries, some more or less complete/maintained than others. EF and Dapper are by far the most popular libraries folks are using on top of Postgres, but there are alternatives, and using the ADO interface on its own works fine (I've done this in very small projects to limit dependencies).

[0] https://www.npgsql.org/doc/index.html


Shameless plug: I wrote a DDNS service in Go [0] that uses Netlink on Linux and the IP Helper API on Windows to monitor network interface addresses in the most efficient way possible. As a result of working on this project, I sent 3 separate CLs to the x/sys module.

[0] https://github.com/database64128/ddns-go

[1] https://go-review.googlesource.com/c/sys/+/597915

[2] https://go-review.googlesource.com/c/sys/+/598895

[3] https://go-review.googlesource.com/c/sys/+/603755


> As a result of working on this project, I sent 3 separate CLs to the x/sys module.

Good one, lol.


This is one of the many things where Go just takes care of automatically. Since Go 1.19, if you import the os package, on startup, the open file soft limit will be raised to the hard limit: https://github.com/golang/go/commit/8427429c592588af8c49522c...


Seems like a good idea but I do wonder what the cost is as the overhead of allocate the extra resource space (whatever it is) would be added to every Go application.


Raising the soft limit to the hard limit is also recommended by the author of systemd: https://0pointer.net/blog/file-descriptor-limits.html

I doubt the kernel would actually allocate the resource space upfront. Like SO_SNDBUF and SO_RCVBUF, it's probably only allocated when it's actually needed.


It's just a limit, you pay the cost when you open the file descriptor


Just write `defer v.Close()`? In almost all cases, `close(2)` errors can be safely ignored. Rust also does this: https://github.com/rust-lang/rust/blob/792fc2b033aea7ea7b766...


I don’t think you want to do this for files you’ve opened for writing.

In fact it’s quite common to “commit” on close, at least from what I’ve seen.


> In fact it’s quite common to “commit” on close, at least from what I’ve seen.

close(2) does not "commit". You have to call v.Sync() (i.e. fsync(2)) for that.

From man 2 close:

       A successful close does not guarantee that the data has been successfully saved to disk, as the kernel uses the buffer cache  to  defer  writes.   Typi‐
       cally,  filesystems  do  not flush buffers when a file is closed.  If you need to be sure that the data is physically stored on the underlying disk, use
       fsync(2).  (It will depend on the disk hardware at this point.)


I think we’re talking past each other.

I was not talking about file descriptors; rather I was talking about the fact that it’s common for Go libraries to do interesting and useful things when you call the `Close()` method on a type. `Close()` is idiomatic go for resource cleanup.

You might wait until close to populate a length and or checksum field in a message header. Or close could submit a buffer of log events to a remote aggregation endpoint.

I’m not saying I agree with APIs that are designed that way, but it’s common enough that you should assume the error return value is significant unless you know otherwise (for Go)


Disable Windows Defender on your main rig and try again?


I just finished adding UDP GRO & GSO support to my WireGuard proxy software. The work involved rewriting a large part of the program.

https://github.com/database64128/swgp-go

For those who don't know, UDP Generic Receive Offload and Generic Segmentation Offload allow you to receive and send multiple same-sized UDP packets coalesced in a single buffer (or many in an iovec but you really shouldn't). Compared to calling sendmsg(2) on individual packets, sending them coalesced in one call traverses the kernel network stack exactly once, thus has significantly lower overhead.

wireguard-go and many QUIC implementations use the same trick to improve throughput. Unfortunately the in-kernel WireGuard driver does not take advantage of UDP GSO, and swgp-go had to cope with that by attempting to coalesce multiple unsegmented messages received in a single recvmmsg(2) call.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: