StarFive VisionFive 2

Basic information

Board URL (official): https://www.starfivetech.com/en/site/boards
Board purchased from: youyeetoo
Board purchase date: 2023-01-05
Board specs (as tested): Dual Gigabit Ethernet
Board price (as tested): $85.10

Linux/system information
# output of `neofetch`
       _,met$$$$$gg.          user@starfive
    ,g$$$$$$$$$$$$$$$P.       -------------
  ,g$$P"     """Y$$.".        OS: Debian GNU/Linux bookworm/sid riscv64
 ,$$P'              `$$$.     Host: StarFive VisionFive V2
',$$P       ,ggs.     `$$b:   Kernel: 5.15.0-starfive
`d$$'     ,$P"'   .    $$$    Uptime: 6 mins
 $$P      d$'     ,    $$P    Packages: 1035 (dpkg)
 $$:      $$.   -    ,d$$'    Shell: bash 5.1.16
 $$;      Y$b._   _,d$P'      Resolution: 1920x1080
 Y$$.    `.`"Y$$$$P"'         Terminal: /dev/pts/0
 `$$b      "-.__              CPU: (4) @ 1.500GHz
  `Y$$                        Memory: 262MiB / 7927MiB
   `Y$$.
     `$$b.
       `Y$$b.
          `"Y$b._
              `"""

# output of `uname -a`
Linux starfive 5.15.0-starfive #1 SMP Mon Dec 19 07:56:37 EST 2022 riscv64 GNU/Linux

Benchmark results
CPU

Geekbench: (78 single / 276 multi - https://browser.geekbench.com/v5/cpu/20379272)
TODO Gflops (geerlingguy/top500-benchmark HPL result)

Power

Idle power draw (at wall): 3.1 W
Maximum simulated power draw (stress-ng --matrix 0): 5.3 W
During Geekbench multicore benchmark: 5.2 W
During top500 HPL benchmark: TODO W

Disk
SanDisk Extreme 128GB microSD

Benchmark
Result

fio 1M sequential read
23.6 MB/s

iozone 1M random read
21.02 MB/s

iozone 1M random write
19.40 MB/s

iozone 4K random read
5.82 MB/s

iozone 4K random write
2.83 MB/s

KIOXIA XG6 1GB NVMe SSD

Benchmark
Result

fio 1M sequential read
149 MB/s

iozone 1M random read
237.35 MB/s

iozone 1M random write
242.66 MB/s

iozone 4K random read
27.87 MB/s

iozone 4K random write
72.73 MB/s

curl https://raw.githubusercontent.com/geerlingguy/pi-cluster/master/benchmarks/disk-benchmark.sh | sudo bash
Run benchmark on any attached storage device (e.g. eMMC, microSD, NVMe, SATA) and add results under an additional heading. Download the script with curl -o disk-benchmark.sh [URL_HERE] and run sudo DEVICE_UNDER_TEST=/dev/sda DEVICE_MOUNT_PATH=/mnt/sda1 ./disk-benchmark.sh (assuming the device is sda).
Also consider running PiBenchmarks.com script.
Network
iperf3 results:

iperf3 -c $SERVER_IP: 937 Mbps
iperf3 --reverse -c $SERVER_IP: 774 Mbps
iperf3 --bidir -c $SERVER_IP: 941 Mbps up / 262 Mbps down

I tested both 1 Gbps interfaces, and they both worked with similar results, and I could connect to two different IPs at once.
GPU

TODO: Haven't determined standardized benchmark yet. See Issue #2.

Memory

TODO: Haven't determined standardized benchmark yet. See Issue #2.

A few thoughts on methodology with a new platform like RISC-V:
Crypto performance:
This is two times a JH7110 board (Star64 and StarFive VisionFive V2) running exactly same OS image but different kernel config / device-tree settings:

Clockspeed
Kernel
Distro
7-zip multi
7-zip single
AES
memcpy
memset

1750 MHz
5.15
Sid riscv64
4820
1396
28970
1170
1120

1500 MHz
5.15
Sid riscv64
4040
1182
6830
1150
860

The 1st is slightly overclocked which ends up with better 7-zip scores, better memset numbers and way better AES scores (openssl speed -elapsed -evp aes-${bytelength}-cbc). At 1750 MHz (17% higher cpufreq) the crypto score gain is an impressive 424%! Or is it the hardware Star64 vs. StarFive VisionFive V2 (both boards being almost the same)?
Is that even possible? Of course not, it's 'OpenSSL 3.0.5, built on 5 Jul 2022' vs. 'OpenSSL 1.1.1f, built on 31 Mar 2020' (and that's why sbc-bench -j will always print the OpenSSL version since it might explain differing numbers).
On every 'new' platform software needs to be optimized. Even if the platform isn't that new any more – see this refreshing bit about a few lines NEON optimizations needed on ARM to really outperform x86 where this level of optimization was standard for a decade already: link to cnx-software)
Same with crypto stuff. On x86  and ARM we have optimized assembler routines since ages or even AES-NI and ARMv8 Crypto Extensions.
While on RISC-V we had only generic C routines but "scalar crypto" extension ratified in the meantime (of course not part of JH7110's silicon since basing on old U74 21G1 cores that predate the ratification). So my assumption is OpenSSL 3.0.5 now making use of optimized (assembler) code and/or the SHA and AES hardware accelerators that these U74 cores provide.
Still being a RISC-V noob I'm trying to ask @brucehoult for clarification (since your review will get a massive target audience compared to other RISC-V reviews).
While your target audience wrt 'SBC performance' most probably just wants a single score and 'less is better' or 'more is better' as only information they deserve better. IMO it's important when reviewing stuff to explain that new hardware usually gets faster over time since software matures and gradually makes use of hardware features. That's why listing a crypto score of 6830 is a bit unfair when comparing with ARM or x86 since those platforms are way older and the software side of things already received much more love. Even if JH7110 will never compete with recent x86 or ARMv8/ARMv9 CPUs due to lack of real crypto extensions.
Benchmarking the benchmark
For whatever reason people blindly trust into the numbers spitten out by a specific benchmark tool. And consumers as usually don't care about individual scores but want one single score or at least one for single-threaded and another for multi-threaded (IMO a horrible choice since those combined scores hide too much and pretty much worthless).
Let's check Geekbench vs. another benchmark. When measuring the JH7110 at 1.5 GHz with 7-zip then it achieves a ~4000 score. 7-zip is all about Integer performance and memory (latency). When choosing a quad-core ARM board with similar score we end up at a Khadas VIM1S for example (based on Amlogic S905Y4: quad A35 @ 2.0 GHz).
Geekbench when looking at total scores tells us JH7110 is only at 60% the S905Y4's performance: https://browser.geekbench.com/v5/cpu/compare/19322441?baseline=17155111
When looking at the individual results view, the board's 'Integer Score' difference is 96 vs. 140 (68%) and 'Crypto Score' is listed as 11 vs. 167 (6.5%). I'm fine with the crypto score but highly doubt the others especially when looking through the individual scores.
Do these benchmark scores represent real-world performance? Or does the rule 'software needs to mature on a new hardware platform' also apply to benchmark software? Most probably yes.
Maybe this is also a hint in the same direction: GB not running on a bunch of RISC-V CPUs due to a problematic instruction.
IMO your target audience deserves these explanations: software needs time and this also applies to benchmarks. And this fact makes maintaining a 'table of benchmark scores' so problematic since software optimization efforts happening in the meantime automagically outdate such a table...

IMO it's important when reviewing stuff to explain that new hardware usually gets faster over time since software matures and gradually makes use of hardware features.

This is quite true—and any RISC-V board will get a lot more of that treatment / extra caveats in my reviews, so don't worry about that! Even with the Pi, every few months some random bug gets squashed that can boost a number here or there (like kernel PTP timing... few people had even tested it until a few months ago), though most of the basics are pretty stable and well-tested at this point.
With the VisionFive 2, very few people have really built anything with it outside of the hardcore tinkerers, so it's going to need a lot of caveats.

For bringup, I used these instructions to flash the simpler (800 MB) buildroot image, scp over the appropriate firmware files, flash them using flashcp, then I could run the latest (-69) version of the official OS release.

For my Kioxia XG6 NVMe SSD, I see it appear as a x1 device at 5.0 GT/sec (so presumably PCIe gen 2):
0001:01:00.0 Non-Volatile memory controller: Toshiba Corporation XG6 NVMe SSD Controller (prog-if 02 [NVM Express])
	Subsystem: Toshiba Corporation XG6 NVMe SSD Controller
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 59
	Region 0: Memory at 38000000 (64-bit, non-prefetchable) [size=16K]
	Capabilities: [40] Express (v2) Endpoint, MSI 00
		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s unlimited, L1 unlimited
			ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+ SlotPowerLimit 0.000W
		DevCtl:	CorrErr- NonFatalErr- FatalErr- UnsupReq-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop- FLReset-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
		LnkCap:	Port #0, Speed 8GT/s, Width x4, ASPM L1, Exit Latency L1 <32us
			ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
		LnkCtl:	ASPM Disabled; RCB 64 bytes, Disabled- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 5GT/s (downgraded), Width x1 (downgraded)
			TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		DevCap2: Completion Timeout: Range AB, TimeoutDis+ NROPrPrP- LTR+
			 10BitTagComp- 10BitTagReq- OBFF Not Supported, ExtFmt+ EETLPPrefix-
			 EmergencyPowerReduction Not Supported, EmergencyPowerReductionInit-
			 FRS- TPHComp- ExtTPHComp-
			 AtomicOpsCap: 32bit- 64bit- 128bitCAS-
		DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis+ LTR- OBFF Disabled,
			 AtomicOpsCtl: ReqEn-
		LnkCap2: Supported Link Speeds: 2.5-8GT/s, Crosslink- Retimer- 2Retimers- DRS-
		LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis-
			 Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
			 Compliance De-emphasis: -6dB
		LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete- EqualizationPhase1-
			 EqualizationPhase2- EqualizationPhase3- LinkEqualizationRequest-
			 Retimer- 2Retimers- CrosslinkRes: unsupported
	Capabilities: [80] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [90] MSI: Enable- Count=1/32 Maskable+ 64bit+
		Address:<PHONE_NUMBER>000000  Data: 0000
		Masking: 00000000  Pending: 00000000
	Capabilities: [b0] MSI-X: Enable+ Count=33 Masked-
		Vector table: BAR=0 offset=00002000
		PBA: BAR=0 offset=00003000
	Capabilities: [100 v2] Advanced Error Reporting
		UESta:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UEMsk:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UESvrt:	DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
		CESta:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr-
		CEMsk:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr+
		AERCap:	First Error Pointer: 00, ECRCGenCap- ECRCGenEn- ECRCChkCap- ECRCChkEn-
			MultHdrRecCap- MultHdrRecEn- TLPPfxPres- HdrLogCap-
		HeaderLog: 00000000 00000000 00000000 00000000
	Capabilities: [260 v1] Latency Tolerance Reporting
		Max snoop latency: 0ns
		Max no snoop latency: 0ns
	Capabilities: [300 v1] Secondary PCI Express
		LnkCtl3: LnkEquIntrruptEn- PerformEqu-
		LaneErrStat: 0
	Capabilities: [400 v1] L1 PM Substates
		L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1- ASPM_L1.2+ ASPM_L1.1- L1_PM_Substates+
			  PortCommonModeRestoreTime=60us PortTPowerOnTime=100us
		L1SubCtl1: PCI-PM_L1.2- PCI-PM_L1.1- ASPM_L1.2- ASPM_L1.1-
			   T_CommonMode=0us LTR1.2_Threshold=0ns
		L1SubCtl2: T_PwrOn=10us
	Kernel driver in use: nvme

But in benchmarks (see OP, and also: https://pibenchmarks.com/benchmark/66979/), I'm only seeing about 200 MB/sec sequential read/write, much less than the 350-400 I'd expect.

First attempt at running the top500 benchmark (HPL) I ran into this error during pip3 install ansible:
Collecting cryptography
  Downloading cryptography-39.0.1.tar.gz (603 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 603.6/603.6 kB 5.7 MB/s eta 0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... error
  error: subprocess-exited-with-error

  × Getting requirements to build wheel did not run successfully.
  │ exit code: 1
  ╰─> [29 lines of output]

              =============================DEBUG ASSISTANCE==========================
              If you are seeing an error here please try the following to
              successfully install cryptography:

              Upgrade to the latest pip and try again. This will fix errors for most
              users. See: https://pip.pypa.io/en/stable/installing/#upgrading-pip
              =============================DEBUG ASSISTANCE==========================

      Traceback (most recent call last):
        File "/usr/lib/python3/dist-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
          main()
        File "/usr/lib/python3/dist-packages/pip/_vendor/pep517/in_process/_in_process.py", line 345, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
        File "/usr/lib/python3/dist-packages/pip/_vendor/pep517/in_process/_in_process.py", line 130, in get_requires_for_build_wheel
          return hook(config_settings)
        File "/usr/lib/python3/dist-packages/setuptools/build_meta.py", line 162, in get_requires_for_build_wheel
          return self._get_build_requires(
        File "/usr/lib/python3/dist-packages/setuptools/build_meta.py", line 143, in _get_build_requires
          self.run_setup()
        File "/usr/lib/python3/dist-packages/setuptools/build_meta.py", line 158, in run_setup
          exec(compile(code, __file__, 'exec'), locals())
        File "setup.py", line 18, in <module>
          from setuptools_rust import RustExtension
        File "/tmp/pip-build-env-o89jx04a/overlay/local/lib/python3.10/dist-packages/setuptools_rust/__init__.py", line 1, in <module>
          from .build import build_rust
        File "/tmp/pip-build-env-o89jx04a/overlay/local/lib/python3.10/dist-packages/setuptools_rust/build.py", line 23, in <module>
          from setuptools.command.build import build as CommandBuild  # type: ignore[import]
      ModuleNotFoundError: No module named 'setuptools.command.build'
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error

× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.

I tried pip3 install --upgrade pip, and installed Ansible again... now getting another error about missing a rust compiler:
      running build_rust

          =============================DEBUG ASSISTANCE=============================
          If you are seeing a compilation error please try the following steps to
          successfully install cryptography:
          1) Upgrade to the latest pip and try again. This will fix errors for most
             users. See: https://pip.pypa.io/en/stable/installing/#upgrading-pip
          2) Read https://cryptography.io/en/latest/installation/ for specific
             instructions for your platform.
          3) Check our frequently asked questions for more information:
             https://cryptography.io/en/latest/faq/
          4) Ensure you have a recent Rust toolchain installed:
             https://cryptography.io/en/latest/installation/#rust

          Python: 3.10.5
          platform: Linux-5.15.0-starfive-riscv64-with-glibc2.33
          pip: n/a
          setuptools: 67.2.0
          setuptools_rust: 1.5.2
          rustc: n/a
          =============================DEBUG ASSISTANCE=============================

      error: can't find Rust compiler

      If you are using an outdated pip version, it is possible a prebuilt wheel is available for this package but pip is not able to install from it. Installing from the wheel would avoid the need for a Rust compiler.

      To update pip, run:

          pip install --upgrade pip

      and then retry package installation.

      If you did intend to build this package from source, try installing a Rust compiler from your system package manager and ensure it is on the PATH during installation. Alternatively, rustup (available at https://rustup.rs) is the recommended way to download and update the Rust compiler toolchain.

      This package requires Rust >=1.48.0.
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for cryptography
  Building wheel for MarkupSafe (setup.py) ... done
  Created wheel for MarkupSafe: filename=MarkupSafe-2.1.2-cp310-cp310-linux_riscv64.whl size=24451 sha256=7fbd78192601d02b42ecc28c0b76d24ecfcefac99a36accc953ec7249179a3e0
  Stored in directory: /home/user/.cache/pip/wheels/54/8e/98/3c8a462676f35ac84e7e2a886d2e90c50c796b73f4cd1f351f
Successfully built PyYAML MarkupSafe
Failed to build cryptography
ERROR: Could not build wheels for cryptography, which is required to install pyproject.toml-based project

Putting that on pause for now.

@ThomasKaiser - I ran your sbc-bench script (downloaded lastest revision from GitHub) and it looks like it's not able to pull the CPU temps:
user@starfive:~$ sudo /bin/bash ./sbc-bench.sh -j
sudo: unable to resolve host starfive: Name or service not known
Starting to examine hardware/software for review purposes...

Average load and/or CPU utilization too high (too much background activity). Waiting...

Checking cpufreq OPP. Done.
Executing RAM latency tester. Done.
Executing OpenSSL benchmark. Done.
Checking cpufreq OPP again. Done (2 minutes elapsed).

It seems neither throttling occured nor too much background activity.

Full results uploaded to http://ix.io/4npK

# StarFive VisionFive V2

Tested on Tue, 07 Feb 2023 22:40:33 +0000. Full info: [http://ix.io/4npK](http://ix.io/4npK)

## General information:

    StarFive JH7110, Kernel: riscv64, Userland: riscv64

    CPU sysfs topology (clusters, cpufreq members, clockspeeds)
                     cpufreq   min    max
     CPU    cluster  policy   speed  speed   core type
      0       -1        0      375    1500   sifive,u74-mc
      1       -1        0      375    1500   sifive,u74-mc
      2       -1        0      375    1500   sifive,u74-mc
      3       -1        0      375    1500   sifive,u74-mc

## Governors (tradeoff between performance and idle consumption):

Original settings:

    cpufreq-policy0: ondemand / 1500 MHz (conservative ondemand userspace powersave performance schedutil)

Tuned settings:

    cpufreq-policy0: performance / 1500 MHz

## Clockspeeds:

Before:

    cpu0 (sifive,u74-mc): OPP: 1500, Measured: 1499

After:

    cpu0 (sifive,u74-mc): OPP: 1500, Measured: 1499

## Software versions:

  * Debian GNU/Linux bookworm/sid
  * Compiler: /usr/bin/gcc (Debian 11.3.0-3) 11.3.0 / riscv64-linux-gnu
  * OpenSSL 1.1.1f, built on 31 Mar 2020
  * Kernel 5.15.0-starfive / CONFIG_HZ=100

Kernel 5.15.0 is not latest 5.15.91 LTS that was released on 2023-02-01.

Please check https://endoflife.date/linux for details. It is somewhat likely
that a lot of exploitable vulnerabilities exist for this kernel as well as
many unfixed bugs. Better upgrade to a supported version ASAP.

All known settings adjusted for performance. System now ready for benchmarking.
Once finished stop with [ctrl]-[c] to get info about throttling, frequency cap
and too high background activity all potentially invalidating benchmark scores.

 Done.

Clockspeeds now:

    cpu0 (sifive,u74-mc): OPP: 1500, Measured: 1499

I also re-ran Geekbench 5 after the script was up and running:

Before: https://browser.geekbench.com/v5/cpu/20379272
After: https://browser.geekbench.com/v5/cpu/20380267

(Just as a point of reference)

I ran your sbc-bench script (downloaded lastest revision from GitHub) and it looks like it's not able to pull the CPU temps

Can you please provide output of cat /sys/devices/virtual/thermal/thermal_zone?/type?

As for the identical Geekbench scores 'before/after'... in general the GB scores since Nov 2022 look all pretty similar: https://browser.geekbench.com/search?q=5.15.0-starfive
That could be an indication this kernel keeping the CPU cores all the time up at highest clockspeed regardless of the governor (something a sbc-bench -m running in idle could maybe confirm – that's a simple monitoring mode reporting sysfs clockspeeds without changing anything). If that's the case consumption (monitoring) in idle is flawed.
Talking about clockspeeds we need to keep in mind that early benchmark results were done with settings limiting the CPU cores to 1250 MHz, the 1.5GHz were only enabled later. Unfortunately Geekbench doesn't measure clockspeeds but reports only sysfs values that might be off by a little or a lot.
That's all the results collected in sbc-bench standard mode (ignore 1st entry since this was @Icenowy doing reliability testing)

Date
Clockspeed
7-zip multi
memcpy
memset

28 Aug 2022
1750 MHz
4820
1170
1120

18 Oct 2022
~1250 MHz
3490
860
790

18 Oct 2022
~1250 MHz
3470
830
790

09 Jan 2023
1500 MHz
4040
1150
860

05 Jan 2023
1500 MHz
4040
900
830

05 Jan 2023
1500 MHz
4060
910
790

30 Jan 2023
1500 MHz
4040
900
780

30 Jan 2023
1500 MHz
4040
880
770

31 Jan 2023
1500 MHz
4140
1140
850

31 Jan 2023
1500 MHz
4080
1020
820

31 Jan 2023
1500 MHz
4110
970
780

31 Jan 2023
1500 MHz
4040
990
780

在 2023-02-08星期三的 01:42 -0800，ThomasKaiser写道：

I ran your sbc-bench script (downloaded lastest revision from
GitHub) and it looks like it's not able to pull the CPU temps

Can you please provide output of cat /sys/devices/virtual/thermal/thermal_zone?/type?
BTW: I've 15 JH7110 results collected but the only one where a
thermal sensor below /sys/devices/virtual/thermal/ could be
determined was @Icenowy's submission: Thermal source:
/sys/devices/virtual/thermal/thermal_zone0/ (cpu-
thermal). But since she's a wizard I would assume
she hacked DT or kernel prior to do any testings.

They made their thermal sensor driver inside hwmon subsystem, although
it seems to be registering thermal zone.
I built my own kernel (and my board is Star64 instead of VisionFive2).

Though on all of them sensors listed the same 120e0000.tmon-isa- 0000 node with something like temp1:        +45.2 C
As such please also provide output from cat /sys/class/hwmon/hwmon?/name

Still being a RISC-V noob I'm trying to ask @brucehoult for clarification (since your review will get a massive target audience compared to other RISC-V reviews).

I don't really know exactly what is implemented in this version of the U74 core. The B extension I'm pretty is there. Scalar crypto I don't know.
Unlike prominent youtube reviewers such as Jeff, Christopher, Gary I don't yet have a board. I put in my order on Kickstarter in the first hour or so it was open, back in August. As backer #14 I have a "Super Early Bird 4 GB" coming (supposedly in November but it wasn't), and as backer #18 (I made a new account with a different email) I have an "Early Bird 8 GB coming (supposed to be in February). I don't have either yet, but they both shipped together (I mean the same day, different packages) on .. well, tracking was created on Jan 6, "shipment arrived at facility on Jan 21". They are both now in NZ with status "in transit to local depot". All timestamps are within 5 minutes of each other (usually the same minute) for both packages. Maybe I'll have them tomorrow, but surely sometime next week.
And then I can try to get them going and do some probing. I'm probably going to have to write boot loader code to give them a proper probe in their back doors and see what is really there. No promises it will be right away, especially as I'm preparing for a business trip 18-26.
As for the point about individual Geekbench benchmarks. I agree. With early boards and early CPU cores such as these, you get far more insight into looking at each result individually, not the headline number.
If you don't have AES and SHA instructions then, yes, those benchmarks are going to really really suck. RISC-V as an ISA has those instructions, but they won't be in chips on boards until probably next year.
Is it fair to include AES and SHA benchmarks in your evaluation of this board? Well, if what you do all day is SHA because you're mining bitcoin, then yes, sure. Otherwise, it's only really fair to look at the effect that slow AES or whatever has on things that normal people actually do, such as ssh/scp/https. Which might well be quite minor. Why not benchmark those?
The same for benchmarks that use SIMD, which again we need to wait 12 months or so for RISC-V chips to arrive with. If your use-case is heavy media processing then, yeah, buy something else. (although maybe there will eventually be support for the GPU doing that ... does PowerVR even support GPGPU stuff? I don't know.)
The benchmark I personally care about is basically ... compiling code. autoconf -> cmake -> ninja -> gcc -> as -> ld etc.
My two year old HiFive Unmatched does pretty well on that against a Pi 4, and I expect this board to also.
 Like all micro-benchmarks it's kind of crappy, but it's I think just as representative of a CPU core's performance (out to L1 cache, not including RAM or disk etc) as the similar Dhrystone and Coremark. But with the benefit of being smaller and simpler code, easy to build, deliberately quite resistant to compiler optimisation tricks.  But looking at A64 as the thing you want to compare to RV64, the HiFive Unmatched is 0.792 as fast as a Pi 4, and 1.99 as fast as a Pi 3 (sadly I don't have an A64 time for Pi 3). It's 1.27 times as fast as an Odroid C2 (a much better board than Pi 3).
I'd love to have figures for an A55 board, which is the most similar Arm microarchitecture, but don't have one.

But in benchmarks (see OP, and also: https://pibenchmarks.com/benchmark/66979/), I'm only seeing about 200 MB/sec sequential read/write

How does /sys/module/pcie_aspm/parameters/policy look like?

But in benchmarks (see OP, and also: https://pibenchmarks.com/benchmark/66979/), I'm only seeing about 200 MB/sec sequential read/write

How does /sys/module/pcie_aspm/parameters/policy look like?

Note that the RAM speed might not be much more than 200 MB/sec. It's not on the HiFive Unmatched. L2 cache stream detection & prefetch were implemented (from memory) in the December 2021 version of the U74, while we believe this uses the March 2021 version.
The AllWinner D1 is a slower CPU, but actually has a decent DRAM interface, and manages 1100 MB/s on large RAM to RAM memcpy().
Well, hopefully I can try it soon. Current status "With courier for delivery 08:07am, 10 February 2023 , Whangarei". The rural delivery usually comes by here around 4 PM, so ... (11 AM now)

Note that the RAM speed might not be much more than 200 MB/sec.

At least tinymembench shows this wrt memory bandwidth on this board at 1.5 GHz (see above):
standard memcpy                                      :   1154.1 MB/s (0.8%)
standard memset                                      :    858.7 MB/s (1.2%)

Unfortunately not a single execution for the HiFive Unmatched has been submitted for my sbc-bench results list.

I can't figure out from http://ix.io/4kHv what the buffer size is for those copies.

I can't figure out from http://ix.io/4kHv what the buffer size is for those copies.

Me neither, can only link to project page: https://github.com/ssvb/tinymembench
Do you have a tool recommendation for quick and reliable bandwidth measurements? tinymembench is orphaned and takes ages...

@brucehoult - Have you gotten your board yet? After my initial stab, I've been following some of the progress for support for hardware video encode/decode among other things, and I may pull it out for some more testing next week.
I necessarily have to unplug and stash away the board when I am trying to get some other work done, otherwise I get sucked in for a day or two at a time :D

I'm also trying to get HDMI working. Right now my monitor doesn't show anything at all (and doesn't even flash to indicate something was being output or tested), and I get the following with modetest:
user@starfive:~$ sudo modetest -M starfive -c
sudo: unable to resolve host starfive: Name or service not known
Connectors:
id	encoder	status		name		size (mm)	modes	encoders
116	115	connected	HDMI-A-1       	510x290		3	115
  modes:
	index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
  #0 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
  #1 1280x720 60.00 1280 1390 1430 1650 720 725<PHONE_NUMBER>0 flags: phsync, pvsync; type: driver
  #2 640x480 59.94 640 656 752 800 480 490<PHONE_NUMBER>5 flags: nhsync, nvsync; type: driver
  props:
	1 EDID:
		flags: immutable blob
		blobs:

		value:
			00ffffffffffff0022f0643001010101
<PHONE_NUMBER>331d782edd45a3554fa027
			125054a1080081c081809500a9c0b300
			d1c001010101023a801871382d40582c
			4500fd1e1100001e000000fd00324c18
			5e14000a202020202020000000fc0048
<PHONE_NUMBER>310a2020202020000000ff
<PHONE_NUMBER>3039315959430a202000d2
	2 DPMS:
		flags: enum
		enums: On=0 Standby=1 Suspend=2 Off=3
		value: 3
	5 link-status:
		flags: enum
		enums: Good=0 Bad=1
		value: 0
	6 non-desktop:
		flags: immutable range
		values: 0 1
		value: 0
	4 TILE:
		flags: immutable blob
		blobs:

		value:

Reading through this post I will try to debug it and get HDMI.

Created a forum post on RVSpace: Can't get HDMI Out on Debian image (modetest either)

Re-testing things with the -69 (latest) image, it seems there are more annoyances, like lspci is not even present. I had to run sudo apt install pciutils to get it.

Going to attempt to get the AMD Radeon HD 7470 working on this board using these instructions. Supposedly no patches required.
Neofetch shows it if I have it connected via my PCIe 1x to 16x M.2 to slot adapter:
GPU: AMD ATI Radeon HD 7470/8470 / R5 235/310 OEM

lspci now shows Kernel modules: radeon, so I ran sudo modprobe radeon and got an error (failed to load firmware):
[  256.739177] [drm] radeon kernel modesetting enabled.
[  256.744687] pci 0001:00:00.0: enabling device (0000 -> 0002)
[  256.750477] radeon 0001:01:00.0: enabling device (0000 -> 0002)
[  256.757305] [drm] initializing kernel modesetting (CAICOS 0x1002:0x6778 0x1028:0x2120 0x00).
[  256.765940] [drm:radeon_device_init [radeon]] *ERROR* Unable to find PCI I/O BAR
[  257.018200] [drm:radeon_atombios_init [radeon]] *ERROR* Unable to find PCI I/O BAR; using MMIO for ATOM IIO
[  257.031557] ATOM BIOS: C26411
[  257.034668] [drm] GPU not posted. posting now...
[  257.049191] radeon 0001:01:00.0: VRAM: 1024M 0x0000000000000000 - 0x000000003FFFFFFF (1024M used)
[  257.058129] radeon 0001:01:00.0: GTT: 1024M 0x0000000040000000 - 0x000000007FFFFFFF
[  257.065873] [drm] Detected VRAM RAM=1024M, BAR=256M
[  257.070785] [drm] RAM width 64bits DDR
[  257.074712] [drm] radeon: 1024M of VRAM memory ready
[  257.079772] [drm] radeon: 1024M of GTT memory ready.
[  257.084867] [drm] Loading CAICOS Microcode
[  257.089208] radeon 0001:01:00.0: Direct firmware load for radeon/CAICOS_pfp.bin failed with error -2
[  257.098443] ni_cp: Failed to load firmware "radeon/CAICOS_pfp.bin"
[  257.104668] [drm:evergreen_init [radeon]] *ERROR* Failed to load firmware!
[  257.115135] radeon 0001:01:00.0: Fatal error during GPU init
[  257.120863] [drm] radeon: finishing device.
[  257.132377] [drm] radeon: ttm finalized
[  257.136664] radeon: probe of 0001:01:00.0 failed with error -2
[  257.136678] Unable to handle kernel access to user memory without uaccess routines at virtual address<PHONE_NUMBER>000190
[  257.153238] Oops [#1]
[  257.155516] Modules linked in: radeon drm_ttm_helper ttm
[  257.160843] CPU: 2 PID: 408 Comm: X Not tainted 5.15.0 #1
[  257.166248] Hardware name: StarFive VisionFive V2 (DT)
[  257.171390] epc : radeon_driver_open_kms+0x34/0x13c [radeon]
[  257.178159]  ra : radeon_driver_open_kms+0x2e/0x13c [radeon]
[  257.184904] epc : ffffffff01594700 ra : ffffffff015946fa sp : ffffffd00451ba70
[  257.192132]  gp : ffffffff81503480 tp : ffffffe0c1e9d000 t0 : ffffffe0c12b5800
[  257.199359]  t1 :<PHONE_NUMBER>000002 t2 :<PHONE_NUMBER>000000 s0 : ffffffd00451bac0
[  257.206585]  s1 : ffffffe0c7580000 a0 :<PHONE_NUMBER>000001 a1 :<PHONE_NUMBER>000022
[  257.213812]  a2 : ffffffff815132c8 a3 :<PHONE_NUMBER>000000 a4 :<PHONE_NUMBER>000002
[  257.221039]  a5 :<PHONE_NUMBER>000000 a6 : ffffffe0c12b5400 a7 :<PHONE_NUMBER>0004d5
[  257.228266]  s2 :<PHONE_NUMBER>000001 s3 : ffffffe0c12b5400 s4 :<PHONE_NUMBER>000000
[  257.235493]  s5 :<PHONE_NUMBER>000000 s6 : ffffffe0c7580000 s7 : ffffffffc4c85028
[  257.242719]  s8 : ffffffffdead5000 s9 :<PHONE_NUMBER>1e8498 s10:<PHONE_NUMBER>000000
[  257.249946]  s11: ffffffd00451bd38 t3 : ffffffe0c12b5800 t4 :<PHONE_NUMBER>000001
[  257.257173]  t5 :<PHONE_NUMBER>000000 t6 :<PHONE_NUMBER>000000
[  257.262482] status:<PHONE_NUMBER>000120 badaddr:<PHONE_NUMBER>000190 cause:<PHONE_NUMBER>00000d
[  257.270406] [<ffffffff01594700>] radeon_driver_open_kms+0x34/0x13c [radeon]
[  257.278400] [<ffffffff8041b81c>] drm_file_alloc+0x14e/0x1f0
[  257.283981] [<ffffffff8041b96c>] drm_open+0xae/0x1e8
[  257.288945] [<ffffffff8041eff2>] drm_stub_open+0x82/0xf0
[  257.294256] [<ffffffff8012cbb4>] chrdev_open+0x94/0x1f0
[  257.299484] [<ffffffff80125114>] do_dentry_open+0xda/0x27c
[  257.304971] [<ffffffff80126504>] vfs_open+0x1e/0x26
[  257.309850] [<ffffffff80135f2c>] path_openat+0x71e/0xa7c
[  257.315162] [<ffffffff80136c7c>] do_filp_open+0x68/0xe2
[  257.320389] [<ffffffff80126758>] do_sys_openat2+0x7e/0x112
[  257.325875] [<ffffffff80126ace>] sys_openat+0x3a/0x7c
[  257.330924] [<ffffffff800030a2>] ret_from_syscall+0x0/0x2
[  257.336381] ---[ end trace c0514edde63c53d9 ]---

Message from syslogd@starfive at Feb 27 00:37:07 ...
 kernel:[  257.153238] Oops [#1]

That forum post says:

The tricky part is mostly over. You now need to install Mesa packages for userspace GPU drivers, connect your GPU using an M.2 → PCIe riser and it should work.

Didn't see any instructions and I'm less familiar with Mesa than I'd like to admit, so I'll do a little digging.

Trying to manually copy the firmware in place:
git clone --depth 1 --filter=blob:none --sparse https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
cd linux-firmware
git sparse-checkout set radeon
sudo cp -R radeon /lib/firmware

I switched from my HP EliteDisplay E231 to an Atomos Ninja V, and now I can get the internal GPU to output to the display, but it's quite slow, and almost all frames are dropped trying to watch a YouTube video at 1080p.
It seems like OpenGL is not supported at all, and Vulkan may be but I haven't been able to get any demos running at all yet.

I also compiled nouveau and tried running a GTX 750 Ti, but got:
[   56.255130] pci 0001:00:00.0: enabling device (0000 -> 0002)
[   56.260897] nouveau 0001:01:00.0: enabling device (0000 -> 0002)
[   56.267413] nouveau 0001:01:00.0: NVIDIA GM107 (117000a2)
[   56.273024] pcie_plda 2c000000.pcie: msi#0 address_hi 0x0 address_lo 0x190
[   56.555215] nouveau 0001:01:00.0: bios: version <IP_ADDRESS>.29
[   56.705497] pcie_plda 2c000000.pcie: AXI fetch error
[   56.967109] pcie_plda 2c000000.pcie: AXI post error
[   57.227714] pcie_plda 2c000000.pcie: AXI post error
[   57.358036] pcie_plda 2c000000.pcie: AXI fetch error
[   57.618622] pcie_plda 2c000000.pcie: AXI post error
[   57.623499] pcie_plda 2c000000.pcie: AXI fetch error
[   57.748937] pcie_plda 2c000000.pcie: AXI fetch error
[   58.009532] pcie_plda 2c000000.pcie: AXI post error
[   58.270138] pcie_plda 2c000000.pcie: AXI post error
[   58.530744] pcie_plda 2c000000.pcie: AXI post error
[   58.791350] pcie_plda 2c000000.pcie: AXI post error
... [repeating, sometimes with 'fetch error' instead of 'post error']
[   77.685312] rcu: INFO: rcu_sched self-detected stall on CPU
[   77.695761] rcu: 	2-....: (171 ticks this GP) idle=399/1/0x4000000000000002 softirq=4399/4399 fqs=77
[   77.704988] 	(t=2105 jiffies g=2173 q=3919)
[   77.709176] Task dump for CPU 2:
[   77.712403] task:modprobe        state:R  running task     stack:    0 pid:  590 ppid:   589 flags:0x00000008
[   77.722328] Call Trace:
[   77.724775] [<ffffffff800048ac>] dump_backtrace+0x1c/0x24
[   77.730183] [<ffffffff8002c826>] sched_show_task+0x152/0x172
[   77.735848] [<ffffffff8099375e>] dump_cpu_task+0x42/0x4c
[   77.741167] [<ffffffff8099436e>] rcu_dump_cpu_stacks+0xd2/0x10e
[   77.747097] [<ffffffff800663a6>] rcu_sched_clock_irq+0x4c8/0x6ba
[   77.753109] [<ffffffff8006c866>] update_process_times+0xa2/0xca
[   77.759039] [<ffffffff8007a4ba>] tick_sched_timer+0x74/0xd6
[   77.764619] [<ffffffff8006cefa>] __hrtimer_run_queues+0x126/0x18a
[   77.770721] [<ffffffff8006db8a>] hrtimer_interrupt+0xce/0x1da
[   77.776471] [<ffffffff8072051e>] riscv_timer_interrupt+0x30/0x3a
[   77.782485] [<ffffffff8005a69e>] handle_percpu_devid_irq+0x80/0x108
[   77.788761] [<ffffffff8005592c>] handle_domain_irq+0x58/0x88
[   77.794423] [<ffffffff803675a6>] riscv_intc_irq+0x36/0x5e
[   77.799827] [<ffffffff800030b0>] ret_from_exception+0x0/0xc
[   77.805407] [<ffffffff015a6c14>] init_wr32+0x20/0x8e [nouveau]
[   77.942870] pcie_plda 2c000000.pcie: AXI post error
[   78.203473] pcie_plda 2c000000.pcie: AXI post error
... [repeating again]

Here's a detailed guide from @Opvolger on how he got a Radeon 5450 running Quake II! https://github.com/Opvolger/Opvolger/blob/master/starfiveVisionFive2/FedoraATIRadeon5450.md

I had the same error "pcie_plda 2c000000.pcie: AXI post error". My problem was the power supply to the PCIe board. It was not powerful enough... So put a complete ATX power supply on it.

For the errors for the AMD video card. You need to add the firmware blobs to the kernel (see my readme from GitHub). Took my minimum 2 hours to figure that out.

pcie_plda 2c000000.pcie: AXI post error

Ah... that makes sense—I only had my little spare 20W adapter hooked up, and the 750 Ti can draw up to 60W I think. I'll have to have another go.
And for AMD, I did put the firmware in place (see comment a few above), but I am running into conflicts with the default xorg setup in the -69 Debian image. Apparently others have just switched to another userland to get around it (like you did with Fedora!). I just didn't have time to dig in further yet.
Plenty to test in the future :D

@brucehoult - Have you gotten your board yet?

Yes! On Friday 10th. And then on the 12th Tropical Cyclone Gabrielle arrived and I was without electricity or internet for four days. And then on the 19th-26th I was away from home at a company "all hands" conference. Now trying to catch up on everything. I'll hope to have some time to look at the VF2 in the weekend. And a new image dropped today...
This probably doesn't match your schedule :-(

@brucehoult - Ah, just noticed the forum post (https://forum.rvspace.org/t/visionfive-2-debian-image-202302-released/2132/12) when I glanced at the forums. Looks like a few little annoyances are fixed (like /boot/boot being /boot now, and shipping minimal instead of an 8 GB (!) ISO). But still not getting hw acceleration in Firefox and having some GPU issues it looks like.
Also, the fact the little boot mode switch now works could throw a lot of people off guard (having to switch the dip switches to the right configuration for SD, eMMC, etc. boot).

Yes, this image is under a 700 MB download.
A lot of people will be happy about the "bonus" WIFI dongle they sold us for 8 (?) SGD now working.
The "What's Next - WIP" section in https://rvspace.org/en/project/VisionFive2_Debian_Wiki_202302_Release lists Firefox hardware acceleration and other GUI / GPU improvements.
Give them a month for the next image with improvements in those areas? That would be quick work.

The status of patches for mainline Linux support: https://rvspace.org/en/project/JH7110_Upstream_Plan
Give them some time and it will be all mainline.

Today I posted a video and blog post about the VisionFive 2.

Armbian on VF2 https://www.armbian.com/visionfive2/ Currently only two variants with Ubuntu user-land. HW support wise, similar to stock.

I see that my solution with a PCIe VGA is not working on the latest JH7110_VisionFive2_devel branch. I have findout why... commit 59cf9af678dbfa3d73f6cb86ed1ae7219da9f5c9 is still working (before last week update).

It is working again on the latest commit.
Nvidia GTX 950: text working, no x11
Nvidia GTX 770 an 580: working but less frames than with my Ati Radeon 5450 in Quake2. X11 feels a bit better.  Minetest is flickering and very slow on the 580 and 5 fps on the 770. Firefox crashed after a couple of minutes on YouTube. (Browsing is a little better then the Ati Radeon but less stable).
AMD Radeon Rx 6600: nothing.
So maybe find an AMD Radeon 200 Series, the last chipset with the old Ati kernel drivers? I keep a eye open :)

<EMAIL_ADDRESS>     .,cdxxxoc,.               .:kKMMMNWMMMNk:.        --------------------
    cKMMN0OOOKWMMXo. ;        ;0MWk:.      .:OMMk.     OS: openSUSE Tumbleweed riscv64
  ;WMK;.       .lKMMNM,     :NMK,             .OMW;    Host: StarFive VisionFive V2
 cMW;            'WMMMN   ,XMK,                 oMM'   Kernel: 5.15.0-dirty
.MMc               ..;l. xMN:                    KM0   Uptime: 1 hour, 33 mins
'MM.                   'NMO                      oMM   Packages: 2279 (rpm)
.MM,                 .kMMl                       xMN   Shell: bash 5.2.15
 KM0               .kMM0. .dl:,..               .WMd   Resolution: 2560x1440
 .XM0.           ,OMMK,    OMMMK.              .XMK    DE: Plasma 5.27.2
   oWMO:.    .;xNMMk,       NNNMKl.          .xWMx     WM: kwin
     :ONMMNXMMMKx;          .  ,xNMWKkxllox0NMWk,      Theme: [Plasma], Breeze [GTK2/3]
         .....                    .:dOOXXKOxl,         Icons: [Plasma], breeze [GTK2/3]
                                                       Terminal: konsole
                                                       CPU: (4) @ 1.500GHz
                                                       GPU: AMD ATI Radeon R9 290/390
                                                       Memory: 1524MiB / 7896MiB

The hostname is ubuntu, but I am running openSUSE, with an AMD ATI Radeon R9 290/390. using the amdgpu drivers no the radeon (radeon drivers gives errors). Browsing (Chromium) and Quake2 are running much better now.

You should do a retest (and maybe a new video) once this is all green (e.g. everything has been upstreamed):
https://rvspace.org/en/project/JH7110_Upstream_Plan
Also, watch out for this series of patches, as those enable the GPU of the JH7110:
https://lore.kernel.org/lkml/?q=%40imgtec.com

Also, watch out for this series of patches, as those enable the GPU of the JH7110:
https://lore.kernel.org/lkml/?q=%40imgtec.com
That series would support a series first, then b series that used on JH7110. Besides, retested should be performed on GCC13 or newer. A great performance boost was noticed (1/7 improvement on coremark score)

@geerlingguy Gb v6 results if you want to add: https://browser.geekbench.com/v6/cpu/3784701

@platima - Excellent, thank you!


Feature Request: Publishing job according to Google's Job Postings specs

Google is moving into job search - and YAWIK should use the new options.
As soon as possible, YAWIK should start publishing jobs according to Google's Job Postings specs. Now available only in the US, Google will certainly roll-out the integration of job search into its general search in other parts of the world.

Actually, the spec's are not Google's but available here https://schema.org/JobPosting

Good idea. Since Google now proposes to use JsonLD we can create a filter and a view helper. This makes it much easier to structured data to the job as suggested in #181
Within a job template it should be possible to add the semantic data simply like semanticData()?>


main.js not loading

Hello,
I successfully passed all the steps , and when I launched the app, installation went smoothly, everything went well except for the last thing : loading main.js
I see an empty app that nevers fully load in my app page, and in ngrok the ok message never appears :
GET /assets/main.js
GET /                          200 OK
I attached a screenshot of what I see in the app page, it never fully loads :

Browser console error : Failed to load resource: net::ERR_CONTENT_LENGTH_MISMATCH     main.js
Any help please? I've been struggling with this for days!
Thank you in advance.

hi, i have same problem. Did you find any solution?

Happens intermittently for me. If you go back to the app screen and then click the app from the Shopify UI it usually fixes it.

Hello ,  i have same problem. Did you find any solution?
thx

Closing because this project is now deprecated.


Create a docker/pinry playbook

Need to add a role to install official docker

After testing, pinry does not fit my needs, so useless to have a playbook for it.


Error Importing Tabu

Hello, I have been trying to import dwave tabu, but I have been experiencing some issues.  When importing the package in python3, I get this result:
>>>import tabu
Traceback (most recent call last):
  File "/home/chip/.local/lib/python3.5/site-packages/tabu/tabu_search.py", line 14, in swig_import_helper
    return importlib.import_module(mname)
  File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 666, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 577, in module_from_spec
  File "<frozen importlib._bootstrap_external>", line 914, in create_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
ImportError: /home/chip/.local/lib/python3.5/site-packages/tabu/_tabu_search.so: wrong ELF class: ELFCLASS64

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/chip/.local/lib/python3.5/site-packages/tabu/__init__.py", line 17, in <module>
    from tabu.tabu_search import TabuSearch
  File "/home/chip/.local/lib/python3.5/site-packages/tabu/tabu_search.py", line 17, in <module>
    _tabu_search = swig_import_helper()
  File "/home/chip/.local/lib/python3.5/site-packages/tabu/tabu_search.py", line 16, in swig_import_helper
    return importlib.import_module('_tabu_search')
  File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
ImportError: No module named '_tabu_search'

I suspect that the error has something to do with swig, but I am unsure what to do to resolve it.  Any help would be greatly appreciated.
Thanks

Hi @cogrpar!
This looks like you're using a binary compiled for 64-bit linux, on a 32-bit installation.
Could you provide a bit more context? What's your OS, how did you install the package, are you using venv and how? Thanks.

Hello @randomir sorry for the trouble, I tried installing this package on another machine and I no longer experience an error.  It was probably just an issue with my other computer.

No worries! Let us know if you run into troubles again. Until then, I'm closing this issue. Thanks!


Mekanism Error(s) with IC2 and Buildcraft

Issue description:
Errors randomly get thrown in console by multiple mods, though i'm assuming this issue is
Mekanism related because i'm only running Mekanism cables through my base (and wind generators)
Steps to reproduce:
I'm not quite sure, this issue randomly started happening. Though i'm noticing my machines dont seem to have power, yet the cables are all showing green
Version (make sure you are on the latest version before reporting):
Forge: 1.12.2-<IP_ADDRESS>68
Mekanism: 1.12.2-<IP_ADDRESS>4
Sponge: 1.12.2-2768-7.1.5
https://pastebin.com/547JRDLw

Hmm this looks a lot like you've got what I call 'yo-yo chunkloading', usually caused by one or more mods not checking if a chunk is loaded and so it continually gets loaded on an interaction, but as it's not player loaded, unloads quickly thereafter.
So this means its not very easy to nail this down. It would be appreciated if you could try the following:

Test without sponge and see if the issue remains (it changes a fair amount of things internally)
Try to reproduce with a minimum mod set and minimum in-world setup

This helps us narrow the problem down & with a small world setup you could send it to me for dissection (I can run it in the dev environment with debugger attached). I can't do this with a large modset, and a large world size is a lot of redundant data to sent over the internet.


Question : Close Imap connection?

How can i close a imap connection?
I see the
    /**
     * close connection
     */
    function __destruct() {
        if($this->imap!==false)
            imap_close($this->imap);
    }

but how do i call it?
i have looked at http://php.net/manual/en/language.oop5.decon.php but i did not see the answer there.
Have i overlooked a function?

You can close the connection by unsetting the variable holding the Imap Object (unset $imap).
But I have added a function for explicitly closing the connection.


Conflict with another plugin

Hi,
I'm including "eternicode/bootstrap-datepicker" plugin in the same page as this one and the select doesn't work anymore. It shows the button with the first option as the text, but no options inside. Also, datepicker stops showing any hover or selected effects.
As soon as I remove one of the plugin's css file from the page, the other plugin becomes fully working again.
select:
<select name="categoria" class="selectpicker" data-live-search="true" data-width="100%">

$('.selectpicker').selectpicker();

datepicker:
<div class="input-group date" id="test">
    <input type="text" class="form-control" id="test" />

$('#test').datepicker();

Hello,
We checked your code and after quite some time we started reading issues till we found this one which is the exact same problem than we've.
Here is the fiddle that shows the problem. The problem is NOT the usage of datetimepicker and selectpicker as having both works. The problem comes from boostrap itself. I think that some bootstrap css updated is conflicting with your select css
http://jsfiddle.net/5g2vebhm/1/
EDIT : it's related to boostrap vs boostrap-select as removing the datetimepicker lib doesn't correct the problem

any update on this issue? This is really a huge problem as it totally prevents a lot of dev to use your awesome lib.

The problem is you were using the "Bootstrap 3.2.0" option built into JSFiddle. I unchecked that option and loaded bootstrap separately and it works. http://jsfiddle.net/5g2vebhm/2/

Your solution works fine but it has conflicts with modal windows, i upgraded the JSFiddle for pointing the problem :(

@hurbinal Can you elaborate? What conflicts? Link to the JSFiddle?

sorry, i edited the comment, but the link of JSFiddle is http://jsfiddle.net/5g2vebhm/4/

Removing bootstrap-select completely results in the same problem - so the problem isn't related to bootstrap-select. Upgrading the version of Bootstrap to 3.3.7 fixes the problem.

@caseyjhol I made a couple of changes to the JSFiddle, updating bootstrap make it work, but which version of bootstrap-select and bootstrap-datetimepicker have you used?

I used the same versions that were in that demo. Bootstrap-select hasn't done anything to affect modal z-indexes, so newer versions should work as well.

I found the problem, i was using jQuery 3.X, i have to use 2.1.0 instead :P


SVNH1 Format - Help Request

Is there a way to get kerosene to pull in the SVNH1 format?

I haven't written a kerosene stub for this yet, but street view house numbers format 1 is supported natively by fuel. If you would like this, I can pretty easily add a SVHN format1 stub and example code.

YES!! That would be amazing!
On Fri, Dec 23, 2016 at 12:19 AM, Tom White<EMAIL_ADDRESS>wrote:

I haven't written a kerosene stub for this yet, but street view house
numbers format 1 is supported natively by fuel. If you would like this, I
can pretty easily add a SVHN format1 stub and example code.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/dribnet/kerosene/issues/4#issuecomment-268942168, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ANU-SobxX1n18eDA_LgiMSdXs3ZtDDKJks5rK1n9gaJpZM4K3djZ
.


[bext-ut] create a new port

What does your PR fix?
Fixes #16691
Which triplets are supported/not supported? Have you updated the CI baseline?
This is a header-only library, so every triplet should be available.
Does your PR follow the maintainer guide?
Wish I worked correctly :)
Related Issues
Naming

See #16302. This port is named bext-ut

The error looks trivial, requesting for /azp run. :D

/azp run

Ready to merge.


WIP: Move to preconfigured Resin-SDK

This PR is interesting because it doesn't work, and I'm not sure why.
Having investigated further, I eventually tried just re-running the last master build, and it turns out that nowadays that doesn't pass either, presumably because of changes in Resin itself sometime in the last year.
The error we hit both then and now is a 'no such file or directory', in a deep trace from fatfs from resin-image-fs. I don't really have any context on what exactly this is trying to do, or what changes we've done in the last year that might have broken it. I can dig in more myself if need be, but it seems like using your expert knowledge might be quicker. Any suggestions, or any idea who else might be good to talk to about this?

Before all we should probably switch to modern versions of Node for the test as some of the SDK prereqs won't work on pre 4 anyway if I'm not mistaken.

And I'll try looking into the errors. I don't think we had any breaking changes to our images in the last year. But it would also help to update the test images with the most recent from production.

I didn't find any hints myself.
@jviotti can you please check why the tests are failing on the current master?

Can we reproduce this locally? I'll investigate...

OK, I can reproduce. I'll hopefully have more information in a bit.

Ah, its because back then we used to have config.json on the fourth partition, but its now on the first one. I'll update the test suite images and it should work fine.

See https://github.com/resin-io/resin-config-json/pull/5. Feel free to merge that one and rebase as soon as tests pass.

Ah, makes sense.
On Thu, Jan 19, 2017 at 6:30 PM, Juan Cruz Viotti<EMAIL_ADDRESS>wrote:

See #5 https://github.com/resin-io/resin-config-json/pull/5. Feel free
to merge that one and rebase as soon as tests pass.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/resin-io/resin-config-json/pull/4#issuecomment-273806742,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAgGCKTSY2dEzNh3BISp6-wCLXVGDIaRks5rT4GvgaJpZM4LjUVn
.

--
Eugene Mirotin
Senior Frontend Engineer
site: Resin.io https://resin.io/, twitter: @resin_io
https://twitter.com/resin_io

Rebased onto the new changes, and the tests pass now and I think this is ready to go. Can somebody approve this? I'll merge once that's done.


Payday fixes

Includes #3430.
This fixes the tests that are failing on master (without test fixtures)

@rohitpaulk Rebase on master, eh?

On it...


fix error of returt zero-code and ru linux locale

issue #5

Fixed, since certified CryptoPro CSP 4.0 R4 uses 0x prefix at return code
5.0 is not certified yet


paperless-ng: fix redis connection

Motivation for this change
paperless-ng is not yet compatible with aioredis 2, which was updated
with the last python update, so pin its version to 1.3.1.
Note that #138294 is needed to build ocrmypdf/paperless-ng.
Things done

Built on platform(s)

[x] x86_64-linux
[ ] aarch64-linux
[ ] x86_64-darwin
[ ] aarch64-darwin

[ ] For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
[x] Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
[ ] Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
[ ] Tested execution of all binary files (usually in ./result/bin/)
21.11 Release Notes (or backporting 21.05 Release notes)

[ ] (Package updates) Added a release notes entry if the change is major or breaking
[ ] (Module updates) Added a release notes entry if the change is significant
[ ] (Module addition) Added a release notes entry if adding a new NixOS module

[ ] Fits CONTRIBUTING.md.

@ofborg eval

Do you have an idea about why two tests fail on aarch64?

No idea, it looks like somehow the consumed file is incomplete or corrupted as it fails here: https://github.com/jonaswinkler/paperless-ng/blob/cd43bc1f660f081325c3d03e758cf9436d3e604f/src/documents/tests/test_management_consumer.py#L78

Do you mind filing an issue upstream?

I just had a look at the initial pr (#123046) and aarch64 tests failed there too, so it’s not a regression. If I find the time, I’ll look more at the failures.


How to run job immediately?

Hi, I set my job to run every several seconds like: "schedule.every(t).seconds.do(func)".
Then I find that the job wait to run until t seconds. So how can I make it to run immediately? Thanks.

I believe if you add a .run() on the end of your schedule call, it will execute it right away and add it for rescheduling.
See here

@blakev Thanks. It works.


Update FtpClientProxy reference

PR Summary
Commit e2633a5bd4f0a4f43ebdd971d89eaac9ad1898ff moved the location of FtpClientProxy.cs. This PR adjusts sources to changes.

Thanks for this.


Feature: add support for useful return values

Describe the ~bug~ feature
I'm not sure if this is support is exposed for third party resources but it if its it would be great to have useful return types defined for datadog resources. In CloudFormation's standard set of resources, these are typically accessed via !Ref Foo !GetAtt Foo.Bar.
Resource Name and version
any/all
To Reproduce
n/a
Logs
n/a
Expected behavior
For monitors it would be great to be able to access its datadog hosted url.
Strawman usecase would be stack outputs that expose links to datadog resources
Outputs:
   MyDDMonitorUrl:
      Value: !GetAtt MyDDMonitor.Url

Additional context
Add any other context about the problem here.

Thanks @softprops,
This a good feature indeed. We will take a closer look at how to implement this for all current resources. We will keep you updated.

➕ 1 for this issue.
Here is my use case
Defining two basic DataDog Monitor resources with "query alert" type, and then trying to define third Composite monitor which would use previous two. Composite monitor should have query "monitor1DataDogID && monitor2DataDogID". Instead of being able to use PhysicalResourceID as ID attribute of first two stacked DataDog Monitor resources (with use of !GetAtt DatadogMongoDBCPUIOWaitHighMonitor.ID and with use of !GetAtt DatadogMongoDBCachedMemoryLowMonitor.ID) , I had to hack around with value which DataDog Third-Party CF Resource currently returns as PhysicalResourceID. For example , if DataDog Monitor resource is created through CloudFormation and in DataDog belonging monitor has ID 12345678, then corresponding PhysicalResourceId of that resource in CloudFormation will have value 1.2345678E7 (skewed, malformed number which is not whole number and therefore unusable string of DataDog Monitor ID).
Basic monitor 1
DatadogMongoDBCPUIOWaitHighMonitor:
    Type: Datadog::Monitors::Monitor
    Properties:
      Type: query alert
      Query: !Sub 'avg(last_1m):avg:system.cpu.iowait{replicasetname:${Domain},environment:${environment}} by {host} > 10'
      Name: !Sub 'mongocluster-${Domain}-${environment}: CPU IOwait {{value}} [%] {{comparator}} 10 [%] for host {{host.name}}'
      Message: |
        {{#is_alert}}

        To fix follow these steps:

          1. Check status health of replica in <URL_REDACTED>
          2. If any alerts are active in Mongo Cloud Health, acknowledge them in PagerDuty
          3. Reach out to the team owning this MongoDB domain and look for utilization peaks in Mongo Cloud Health manager!
          4. Try to remediate root cause of the CPU waits spike asap !
          5. Observe memory utilization in response to your remediation actions !
          6. Login to AWS Console in `<REDACTED>` and troubleshoot the instance state:
              3a. check if you can ssh into the node
              3b. check if docker container is running
              3c. check if we had AWS hardware degradation e-mail related to this EC2 instance
        {{/is_alert}}

        {{#is_recovery}}
         Host {{host.name}} is back to normal CPU IO wait with value of {{value}}%!
        {{/is_recovery}}

        Notify: @pagerduty-GlobalPDRouting
        More Information On How This Alert Was Setup: [Incident Management with Pager Duty](<URL_REDACTED>)
      Options:
        Thresholds:
          Critical: 10
          OK: 9.99
          CriticalRecovery: 9.99
        NotifyNoData: false
        RequireFullWindow: true
        NewHostDelay: 120
      DatadogCredentials:
        ApiKey: '{{resolve:secretsmanager:<REDACTED>:apikey}}'
        ApplicationKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:applicationkey}}'

Basic monitor 2
DatadogMongoDBCachedMemoryLowMonitor:
    Type: Datadog::Monitors::Monitor
    Properties:
      Type: query alert
      Query: !Sub 'avg(last_1m):avg:system.mem.cached{replicasetname:${Domain},environment:${environment}} by {host} < 500000000'
      Name: !Sub 'mongocluster-${Domain}-${environment}: Cached memory {{value}} [B] {{comparator}} 500 [MB] for host {{host.name}}'
      Message: |
        {{#is_alert}}

        To fix follow these steps:

          1. Check status health of replica in <URL_REDACTED>
          2. If any alerts are active in Mongo Cloud Health, acknowledge them in PagerDuty
          3. Reach out to the team owning this MongoDB domain and look for utilization peaks in Mongo Cloud Health manager!
          4. Try to remediate root cause of the low system cache asap !
          5. Observe memory utilization in response to your remediation actions !
          6. Login to AWS Console in `<REDACTED>` and troubleshoot the instance state:
              3a. check if you can ssh into the node
              3b. check if docker container is running
              3c. check if we had AWS hardware degradation e-mail related to this EC2 instance
        {{/is_alert}}

        {{#is_recovery}}
         Host {{host.name}} is back to normal values for cached system memory with value of {{value}}!
        {{/is_recovery}}

        Notify: @pagerduty-GlobalPDRouting
        More Information On How This Alert Was Setup: [Incident Management with Pager Duty](<URL_REDACTED>)
      Options:
        Thresholds:
          Critical: 500000000
          OK: 500000001
          CriticalRecovery: 500000001
        NotifyNoData: false
        RequireFullWindow: true
        NewHostDelay: 120
      DatadogCredentials:
        ApiKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:apikey}}'
        ApplicationKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:applicationkey}}'

I would like my third, composite monitor (attention on Query property below) to be defined as:
DatadogMongoDBSwappingWatchCompositeMonitor:
    Type: Datadog::Monitors::Monitor
    DependsOn: [DatadogMongoDBCPUIOWaitHighMonitor, DatadogMongoDBCachedMemoryLowMonitor]
    Properties:
      Type: composite
      Query: !Sub "${DatadogMongoDBCPUIOWaitHighMonitor} && ${DatadogMongoDBCachedMemoryLowMonitor}"
      Name: !Sub 'mongocluster-${Domain}-${environment}: High IOWait and low system cached memory - potential swapping on host {{host.name}}'
      Message: |
        {{#is_alert}}

        There are other two independent alarms for "system.mem.cached" and "system.cpu.iowait" metrics setup - you should check them out (they have same prefix as this monitor) !!!

        To fix follow these steps:

          1. Check status health of replica in <URL_REDACTED>
          2. If any alerts are active in Mongo Cloud Health, acknowledge them in PagerDuty
          3. Reach out to the team owning this MongoDB domain and look for utilization peaks in Mongo Cloud Health manager!
          4. Try to remediate root cause for swapping asap !
          5. Observe memory utilization in response to your remediation actions !
          6. Login to AWS Console in `<REDACTED>` and troubleshoot the instance state:
              3a. check if you can ssh into the node
              3b. check if docker container is running
              3c. check if we had AWS hardware degradation e-mail related to this EC2 instance
        {{/is_alert}}

        {{#is_recovery}}
         Host {{host.name}} potential swapping back to normal !
        {{/is_recovery}}

        Notify: @pagerduty-GlobalPDRouting
        More Information On How This Alert Was Setup: [Incident Management with Pager Duty](<URL_REDACTED>)
      Options:
        NotifyNoData: false
      DatadogCredentials:
        ApiKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:apikey}}'
        ApplicationKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:applicationkey}}'

... instead I had to hack around the returned value for Physical ID of  Datadog::Monitors::Monitor CF resource ( again, attention is on Query property below), with ...
DatadogMongoDBSwappingWatchCompositeMonitor:
    Type: Datadog::Monitors::Monitor
    DependsOn: [DatadogMongoDBCPUIOWaitHighMonitor, DatadogMongoDBCachedMemoryLowMonitor]
    Properties:
      Type: composite
      Query: !Sub
          - "${DatadogMongoDBCPUIOWaitHighMonitorID} && ${DatadogMongoDBCachedMemoryLowMonitorID}"
          - DatadogMongoDBCPUIOWaitHighMonitorID:  !Select [ 0, !Split ["E7", !Join [ "", !Split [ "." , !Ref DatadogMongoDBCPUIOWaitHighMonitor ]] ] ]
            DatadogMongoDBCachedMemoryLowMonitorID: !Select [ 0, !Split ["E7", !Join [ "", !Split [ "." , !Ref DatadogMongoDBCachedMemoryLowMonitor ]] ] ]
      Name: !Sub 'mongocluster-${Domain}-${environment}: High IOWait and low system cached memory - potential swapping on host {{host.name}}'
      Message: |
        {{#is_alert}}

        There are other two independent alarms for "system.mem.cached" and "system.cpu.iowait" metrics setup - you should check them out (they have same prefix as this monitor) !!!

        To fix follow these steps:

          1. Check status health of replica in <URL_REDACTED>
          2. If any alerts are active in Mongo Cloud Health, acknowledge them in PagerDuty
          3. Reach out to the team owning this MongoDB domain and look for utilization peaks in Mongo Cloud Health manager!
          4. Try to remediate root cause for swapping asap !
          5. Observe memory utilization in response to your remediation actions !
          6. Login to AWS Console in `<REDACTED>` and troubleshoot the instance state:
              3a. check if you can ssh into the node
              3b. check if docker container is running
              3c. check if we had AWS hardware degradation e-mail related to this EC2 instance
        {{/is_alert}}

        {{#is_recovery}}
         Host {{host.name}} potential swapping back to normal !
        {{/is_recovery}}

        Notify: @pagerduty-GlobalPDRouting
        More Information On How This Alert Was Setup: [Incident Management with Pager Duty](<URL_REDACTED>)
      Options:
        NotifyNoData: false
      DatadogCredentials:
        ApiKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:apikey}}'
        ApplicationKey: '{{resolve:secretsmanager:<REDACTED>:SecretString:applicationkey}}'

@bkabrda , I would like to try contributing on this issue. Is there some Slack, Matrix/Riot or such open chat community where I can reach out to other contributors for questions?

My use case: I'd like to create an SLO, and then a monitor that alerts if the SLO is violated. The monitor query requires the SLO ID, which would ideally be an output of the SLO resource.

Hi, with the latest major version of the resources, this should now be working as expected. You can reference the ID of a resource directly with !Ref Foo, or any attribute defined in the schema with !GetAtt Foo.Bar.
Regarding the OP, the URL is not a returned attribute of the monitors API, which is why it's not directly available for reference.
However there's a workaround that was suggested by @jirikuncar in this comment
Feel free to comment/reopen this issue if I've missed anything


Dependency on constructs 3.2.7?

I see in package.json that constructs 10.0.5 is in use. However, when I try to install this package, it looks like there's a reference to 3.2.7:
npm ERR! Conflicting peer dependency<EMAIL_ADDRESS>npm ERR! node_modules/constructs
npm ERR!   peer<EMAIL_ADDRESS>from<EMAIL_ADDRESS>npm ERR!   node_modules/@renovosolutions/cdk-library-certbot
npm ERR!     dev<EMAIL_ADDRESS>from the root project

I can correct this using overrides to force to 10, but wanted to confirm that this is safe. Also, any idea why I'd see these conflicts given that it should be 10.0.5?

Is the code on the master branch published somewhere? It looks like I'm getting the v1 branch when I reference the latest published version on npm:
"@renovosolutions/cdk-library-certbot": "1.1.260"


Outer: remove redundancy in parser error message

Consider the following files:
primay.k:
requires "secondary.k"
module PRIMARY
syntax Foo ::= "bar"

endmodule
secondary.k:
module SECONDARY
syntax Foo ::= | "baz"

endmodule
When compiling primary.k, the following error message is generated:
[Error] Outer Parser: Encountered "|".
Was expecting one of: ["non-assoc", , <STRING_REGEX>, "(", "left",
"right", "List", "NeList", <UPPER_ID>, <LOWER_ID>, , <UPPER_ID>, "List",
"NeList", <LOWER_ID>] (ParseException: Encountered " "|" "|"" at line 3, column
18.
Was expecting one of:
"non-assoc" ...
 ...
<STRING_REGEX> ...
"(" ...
"left" ...
"right" ...
"List" ...
"NeList" ...
<UPPER_ID> ...
<LOWER_ID> ...
 ...
<UPPER_ID> ...
"List" ...
"NeList" ...
<LOWER_ID> ...
)
Source(/home/erik/samps-k/secondary.k)
Location(3,18,3,18)
This error message's "ParseException: ..." message is redundant. Remove
this redundancy by not passing the ParseException object when
registering the exception so that the error message looks like the
following:
[Error] Outer Parser: Encountered "|".
Was expecting one of: ["non-assoc", , <STRING_REGEX>, "(", "left",
"right", "List", "NeList", <UPPER_ID>, <LOWER_ID>, , <UPPER_ID>, "List",
"NeList", <LOWER_ID>]
Source(/home/erik/samps-k/secondary.k)
Location(3,18,3,18)
Signed-off-by: Erik Kaneda<EMAIL_ADDRESS>

I know this is not exactly the solution we discussed in #2100 but it's less code so I thought I'd submit for feedback...

This not the correct solution. @radumereuta @dwightguth please review #2102 instead


[General] [Fixed] - Fixes react-native-codegen location within script_phases.sh

Summary
@byCedric did some amazing work to update the codegen location monorepo support. There was just 1 small issue which is in the name of the package: instead of @react-native/codegen it should be react-native-codegen

Changelog
[General] [Fixed] - Fixes react-native-codegen location within script_phases.sh from @react-native/codegen to react-native-codegen

Test Plan
Run eas build --platform ios within a monorepo like Backpack

Hey @peterpme, thanks for the contribution!
I see that this line was changed in https://github.com/facebook/react-native/pull/34804, after we renamed package react-native-codegen to @react-native/codegen. Although its location hasn't changed (it is still present inside packages/react-native-codegen), its also should be available as @react-native/codegen inside node_modules.
We probably changed these lines by a mistake. I don't have much of a context on how its used here, but does this revert fixes your problem, could you please validate that?

This breaks the CI tests, please check e.g. here:

Error: Cannot find module 'react-native-codegen/package.json'

Hi @rshest & @hoxyq thank you! I think there's a version mismatch. Moving forward I believe this should be @react-native/codegen so I will close this out :)


Ensure compatible with Django 1.9/1.10

We should make sure this works with the latest versions of Django so that apps that rely on this can be safely upgraded.

I've added 1.9 and 1.10 to the tox configuration in v0.3.6.


[WIP] Prototype for using buffered uart rx

I would like to get the discussion going on how to best implement (async) uart rx buffering.
In my usecase the hw fifio of 132 bytes quickly overflows when I receive a lot of data from an LTE modem, while doing other tasks. But in other usecases the hw fifo might be enough, thats why I would let it up to the user to decide whether he wants an additional buffer or not.
What do you think of my approach?
(Would you like to see a heapless::blocking_mutex::CriticalSectionMutex<RefCell<..>> instead of a plain static mut to store the buffer? )

Thank you for the initial feedback @MabezDev.
I'll take a look at how embassy-stm32 does it. Although it might take a while until I find the time to refactor this, as I have a lot of other, more pressing issues in the queue.

I've converted this to a draft for the time being, just to help me with keeping track of things. Please feel free to change it back whenever you feel it's ready for review :)

I've decided to abandon this project, as I have too many other things pending at the same time... I might pick it up again in fall.
Instead I've disabled the asnych feature and added a simple buffered interrupt reader using the excellent bbqueue crate. I'll share my code below, for anyone else looking for something similar, until we have a nice solution developed and merged into esp-hal.

Buffered interrupt reader for async uart
/// This file is in parts a copy of the async part of the uart.rs file from the esp-hal crate
/// The async write part is copied 1:1 from the esp-hal crate
/// The async read part is completely rewritten, and it works as follows:
///
/// The main problem with the esp-hal async rx implementation is that it has no buffer except the hardware fifo of 128 bytes.
/// This means that if the async task is not fast enough to read the data from the hardware fifo, the data will be lost.
///
/// Our new implementation uses a BBBuffer to store the data. The BBBuffer is a lock-free ring buffer, and it is filled directly in the interrupt.
/// In order to not wake up the async task for every byte received, we use a signal to wake up the async task when a frame was completed (by rx timeout or atcmd interrupt).
/// The signal also contains the number of bytes available in the buffer at the time of the frame completion isr and whether there was a hw fifo overflow.
///
/// If the interrupt wants to commit a 2nd frame before the async task has read the first frame, the frames will be merged.
/// As a result, the reader will always read one or multiple complete frames.
use bbqueue::BBBuffer;
use core::convert::Infallible;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::signal::Signal;
use embassy_sync::waitqueue::AtomicWaker;
use embedded_io_async::{ErrorType, Read, Write};
use enumset::{EnumSet, EnumSetType};
use hal::macros::interrupt;
use hal::riscv::_export::critical_section;
use hal::uart::Instance;
use pac::uart0::RegisterBlock;

pub struct AsyncUartTx<T: 'static> {
    _uart: hal::UartTx<'static, T>,
}

pub struct AsyncUartRxBuffer<const N: usize> {
    queue: BBBuffer<N>,
    signal: Signal<CriticalSectionRawMutex, FrameCompleteEvent>,
    producer: Option<Producer<N>>,
}

struct Producer<const N: usize> {
    /// The size of the current, unfinished frame
    frame_size: usize,
    /// The buffer to write to
    producer: bbqueue::Producer<'static, N>,
    /// The signal to inform the async task about new frames
    signal: &'static Signal<CriticalSectionRawMutex, FrameCompleteEvent>,
}

struct Consumer<const N: usize> {
    /// how much we can read from the buffer until we reach the end of the current frame
    remaining: usize,
    /// the buffer to read from
    consumer: bbqueue::Consumer<'static, N>,
    /// the signal to wait for new frames
    signal: &'static Signal<CriticalSectionRawMutex, FrameCompleteEvent>,
}

impl<const N: usize> Consumer<N> {
    fn read_remaining(&mut self, mut buf: &mut [u8]) -> usize {
        let mut written = 0;
        while buf.len() > 0 && self.remaining > 0 {
            let grant = self.consumer.read().unwrap();
            let src_buf = grant.buf();
            let len = src_buf.len().min(buf.len()).min(self.remaining);
            buf[..len].copy_from_slice(&src_buf[..len]);
            grant.release(len);
            self.remaining -= len;
            written += len;
            buf = &mut buf[len..];
        }
        written
    }

    async fn read(&mut self, buf: &mut [u8]) -> usize {
        if self.remaining > 0 {
            return self.read_remaining(buf);
        }

        let event = self.signal.wait().await;

        if event.overflow {
            error!("uart RX fifo overflow");
        }

        self.remaining = event.available;
        self.read_remaining(buf)
    }
}

impl<const N: usize> Producer<N> {
    fn append_from_uart(&mut self, uart: &RegisterBlock, overflow: bool, mut frame_complete: bool) {
        let mut fifo_len = uart.status().read().rxfifo_cnt().bits();
        let mut total_written = 0;
        if fifo_len > 0 {
            while let Ok(mut grant) = self.producer.grant_max_remaining(fifo_len as usize) {
                let mut written = 0;
                let buf = grant.buf();
                while fifo_len > 0 && written < buf.len() {
                    buf[written] = uart.fifo().read().rxfifo_rd_byte().bits();
                    written += 1;
                    fifo_len -= 1;
                }
                grant.commit(written);
                total_written += written;
                if fifo_len == 0 {
                    break;
                }
            }

            if total_written > 0 {
                self.frame_size += total_written;
            } else {
                frame_complete = true;
                // This is not an overflow yet, but it will quickly become one because the next isr that comes is ovf.
                // So we wake the task here, even if the frame is not complete yet
            }
        }

        if overflow || frame_complete {
            // If the async reader has not read the previous frame yet, we merge the frames here, otherwise we publish a new one.
            let mut event = self.signal.try_take().unwrap_or(FrameCompleteEvent { available: 0, overflow: false });
            event.overflow |= overflow;
            event.available += self.frame_size;
            self.frame_size = 0;
            self.signal.signal(event);
        }
    }
}

impl<const N: usize> AsyncUartRxBuffer<N> {
    pub fn new() -> Self {
        let queue = BBBuffer::new();
        let signal = Signal::new();
        Self { queue, signal, producer: None }
    }
}

pub struct AsyncUartRx<T: Instance + 'static, const N: usize> {
    _uart: hal::UartRx<'static, T>,
    consumer: Consumer<N>,
}

impl<T> ErrorType for AsyncUartTx<T> {
    type Error = hal::uart::Error;
}

impl<T: Instance, const N: usize> ErrorType for AsyncUartRx<T, N> {
    type Error = Infallible;
}

impl<T> AsyncUartTx<T> {
    pub fn new(uart: hal::UartTx<'static, T>) -> Self {
        Self { _uart: uart }
    }
}

impl<T: Instance, const N: usize> AsyncUartRx<T, N> {
    /// Create a new async UART receiver
    ///
    /// Before passing the rx half of the uart to this constructor,
    /// please configure rx_fifo_full (`set_rx_fifo_full_threshold`)
    /// and configure at least one of rx_timeout (`set_rx_timeout`) or at_amd (`set_at_cmd`)
    ///
    /// # Arguments
    /// * `uart` - The UART Rx instance.
    /// * `rx_buffer` - The buffer to store the received data
    /// * `process_atcmd` - Process data on at cmd interrupt
    /// * `process_tout` - Process data on rx timeout interrupt
    pub fn new(uart_rx: hal::UartRx<'static, T>, rx_buffer: &'static mut AsyncUartRxBuffer<N>, process_atcmd: bool, process_tout: bool) -> Self {
        assert!(process_atcmd || process_tout);
        let (producer, consumer) = rx_buffer.queue.try_split().unwrap();
        let signal = &rx_buffer.signal;
        rx_buffer.producer.replace(Producer { frame_size: 0, producer, signal });

        critical_section::with(|_| unsafe {
            RX_HANDLERS[T::uart_number()] = Some(rx_buffer.producer.as_mut().unwrap());
        });

        let consumer = Consumer { remaining: 0, consumer, signal };

        T::register_block().int_ena().modify(|_, w| {
            if process_atcmd {
                w.at_cmd_char_det_int_ena().set_bit();
            }
            if process_tout {
                w.rxfifo_tout_int_ena().set_bit();
            }
            w.rxfifo_full_int_ena().set_bit();
            w.rxfifo_ovf_int_ena().set_bit();
            w
        });

        Self { _uart: uart_rx, consumer }
    }
}

impl<T: Instance, const N: usize> Drop for AsyncUartRx<T, N> {
    fn drop(&mut self) {
        critical_section::with(|_| unsafe {
            RX_HANDLERS[T::uart_number()] = None;
        });

        T::register_block().int_ena().modify(|_, w| {
            w.at_cmd_char_det_int_ena().clear_bit();
            w.rxfifo_tout_int_ena().clear_bit();
            w.rxfifo_full_int_ena().clear_bit();
            w.rxfifo_ovf_int_ena().clear_bit();
            w
        });
    }
}

const UART_FIFO_SIZE: u16 = 128;
const NUM_UART: usize = 2;

const WAKER_INIT: AtomicWaker = AtomicWaker::new();
static TX_WAKERS: [AtomicWaker; NUM_UART] = [WAKER_INIT; NUM_UART];

#[derive_format_or_debug]
struct FrameCompleteEvent {
    available: usize,
    overflow: bool,
}

trait RxBufferInterruptHandler {
    fn append_from_uart(&mut self, uart: &RegisterBlock, overflow: bool, frame_complete: bool);
}

impl<const N: usize> RxBufferInterruptHandler for Producer<N> {
    fn append_from_uart(&mut self, uart: &RegisterBlock, overflow: bool, frame_complete: bool) {
        self.append_from_uart(uart, overflow, frame_complete);
    }
}

const RX_INIT: Option<&mut dyn RxBufferInterruptHandler> = None;
static mut RX_HANDLERS: [Option<&mut dyn RxBufferInterruptHandler>; NUM_UART] = [RX_INIT; NUM_UART];

// This impl is 1:1 copied from esp-hal
impl<T> Write for AsyncUartTx<T>
where
    T: Instance,
{
    async fn write(&mut self, words: &[u8]) -> Result<usize, Self::Error> {
        let mut count = 0;
        let mut offset: usize = 0;
        loop {
            let mut next_offset = offset + (UART_FIFO_SIZE - T::get_tx_fifo_count()) as usize;
            if next_offset > words.len() {
                next_offset = words.len();
            }

            for byte in &words[offset..next_offset] {
                T::register_block().fifo().write(|w| unsafe { w.rxfifo_rd_byte().bits(*byte) });
                count += 1;
            }

            if next_offset >= words.len() {
                break;
            }

            offset = next_offset;
            UartTxFuture::<T>::new(TxEvent::TxFiFoEmpty.into()).await;
        }

        Ok(count)
    }

    async fn flush(&mut self) -> Result<(), Self::Error> {
        let count = T::get_tx_fifo_count();
        if count > 0 {
            UartTxFuture::<T>::new(TxEvent::TxDone.into()).await;
        }

        Ok(())
    }
}

#[derive(EnumSetType)]
#[derive_format_or_debug]
pub(crate) enum TxEvent {
    TxDone,
    TxFiFoEmpty,
}

pub(crate) struct UartTxFuture<'d, T: Instance> {
    events: EnumSet<TxEvent>,
    phantom: PhantomData<&'d mut T>,
    registered: bool,
}

impl<'d, T: Instance> UartTxFuture<'d, T> {
    pub fn new(events: EnumSet<TxEvent>) -> Self {
        Self {
            events,
            phantom: PhantomData,
            registered: false,
        }
    }

    fn event_bit_is_clear(&self) -> bool {
        let interrupts_enabled = T::register_block().int_ena().read();
        let mut event_triggered = false;
        for event in self.events {
            event_triggered |= match event {
                TxEvent::TxDone => interrupts_enabled.tx_done_int_ena().bit_is_clear(),
                TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty_int_ena().bit_is_clear(),
            }
        }
        event_triggered
    }
}

impl<'d, T: Instance> core::future::Future for UartTxFuture<'d, T> {
    type Output = ();

    fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> Poll<Self::Output> {
        if !self.registered {
            TX_WAKERS[T::uart_number()].register(cx.waker());
            T::register_block().int_ena().modify(|_, w| {
                for event in self.events {
                    match event {
                        TxEvent::TxDone => w.tx_done_int_ena().set_bit(),
                        TxEvent::TxFiFoEmpty => w.txfifo_empty_int_ena().set_bit(),
                    };
                }
                w
            });
            self.registered = true;
        }

        if self.event_bit_is_clear() {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}

impl<'d, T: Instance> Drop for UartTxFuture<'d, T> {
    fn drop(&mut self) {
        // Although the isr disables the interrupt that occurred directly, we need to
        // disable the other interrupts (= the ones that did not occur), as
        // soon as this future goes out of scope.
        let int_ena = &T::register_block().int_ena();
        for event in self.events {
            match event {
                TxEvent::TxDone => int_ena.modify(|_, w| w.tx_done_int_ena().clear_bit()),
                TxEvent::TxFiFoEmpty => int_ena.modify(|_, w| w.txfifo_empty_int_ena().clear_bit()),
            }
        }
    }
}

impl<T, const N: usize> Read for AsyncUartRx<T, N>
where
    T: Instance,
{
    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        Ok(self.consumer.read(buf).await)
    }
}

/// Interrupt handler for all UART instances
/// Clears rx+tx and disables tx interrupts that have occurred and have their enable
/// bit set. The fact that an interrupt has been disabled is used by the tx
/// futures to detect that they should indeed resolve after being woken up.
/// Rx-data is written to a BBBuffer. See note at the top of the file.
fn intr_handler(uart: &RegisterBlock, buffer: &mut Option<&mut dyn RxBufferInterruptHandler>) -> bool {
    let interrupts = uart.int_st().read();
    let interrupt_bits = interrupts.bits(); // = int_raw & int_ena
    if interrupt_bits == 0 {
        return false;
    }

    // Disable tx interrupts that have occurred
    let tx_wake = interrupts.tx_done_int_st().bit_is_set() || interrupts.txfifo_empty_int_st().bit_is_set();
    uart.int_ena().modify(|_, w| {
        if interrupts.tx_done_int_st().bit_is_set() {
            w.tx_done_int_ena().clear_bit();
        }
        if interrupts.txfifo_empty_int_st().bit_is_set() {
            w.txfifo_empty_int_ena().clear_bit();
        }
        w
    });

    let rx_int = interrupts.rxfifo_ovf_int_st().bit_is_set()
        || interrupts.rxfifo_full_int_st().bit_is_set()
        || interrupts.rxfifo_tout_int_st().bit_is_set()
        || interrupts.at_cmd_char_det_int_st().bit_is_set();

    if rx_int {
        if let Some(buffer) = buffer {
            let overflow = interrupts.rxfifo_ovf_int_st().bit_is_set();
            let frame_complete = interrupts.at_cmd_char_det_int_st().bit_is_set() || interrupts.rxfifo_tout_int_st().bit_is_set();
            buffer.append_from_uart(uart, overflow, frame_complete);
        }
    }

    uart.int_clr().write(|w| unsafe { w.bits(interrupt_bits) });
    tx_wake
}

#[interrupt]
fn UART0() {
    let uart = unsafe { &*hal::peripherals::UART0::ptr() };
    let tx = intr_handler(uart, unsafe { &mut RX_HANDLERS[0] });

    if tx {
        TX_WAKERS[0].wake();
    }
}

#[interrupt]
fn UART1() {
    let uart = unsafe { &*hal::peripherals::UART1::ptr() };
    let tx = intr_handler(uart, unsafe { &mut RX_HANDLERS[1] });

    if tx {
        TX_WAKERS[1].wake();
    }
}


Use closetag for XSDs as well as XMLs

-let g:closetag_filenames = "*.xml"
+let g:closetag_filenames = "*.xml,*.xsd"

fixed


Feature Request - Support for SMTP STARTTLS between SMTP client and SMTP proxy

Hello,
When using the SMTP proxy with certificate to create a secure connection between itself and the email client, the proxy will support SMTPS (SMTP Implicit) but won't support SMTP STARTTLS (SMTP Explicit).
Some printers (and apps) only support SMTP STARTTLS as a way to create a secure connection. As an alternative solution, I'm using plain text SMTP between clients and proxy.
I think it would be a usefull feature to have SMTP STARTTLS available between SMTP clients and Email OAuth 2.0 Proxy.
Anyway, thanks for this great tool.

Please read the documentation – this is already supported.

I have read the doc, also done some tests and tried to understand the source
.
When using starttls = True the proxy will handle STARTTLS negotiation with the SMTP server.
It means the data exchanged between client and proxy is in plaintext.
If using 'local_certificate_path' and 'local_key_path' the proxy will support SMTP implicit for incoming connection but won't support SMTP explicit (STARTTLS).
Here is the server part of my config file :
[SMTP-465] server_address = smtp.office365.com server_port = 587 starttls = True local_certificate_path = /config/smtprelay.crt local_key_path = /config/smtprelay.key
With this config,
SMTP Implicit : openssl s_client -connect IP_ADDRESS:465 -crlf is working
SMTP Explicit : openssl s_client -connect IP_ADDRESS:465 -crlf -starttls smtp is not working.

Ah, ok – you are wanting the proxy to simulate STARTTLS for clients that enforce this. This was requested recently, but isn't yet supported by the proxy.
I'm happy to look at adding this feature on a consultancy basis if it needs prioritising.

Yes that's what I'm looking for.
Thanks for your answer.

Thanks for the support – could you try the smtp-local-starttls branch to see a work-in-progress version?
Add local_starttls = True to a SMTP server that has a local certificate, and your SMTP Explicit command from above should now work.
More polishing is needed (for example, server status in the GUI is now not reflected), but this should let you try things out at least.

With the smtp-local-starttls branch, and the following config file the proxy kinda supports STARTTLS command for the local connection.
[SMTP-587]
server_address = smtp.office365.com
server_port = 587
starttls = True
local_starttls = True
local_certificate_path = smtprelay.crt
local_key_path = smtprelay.key
CLI used to test : openssl s_client -connect IP_ADDRESS:587 -crlf -starttls smtp
But when using openssl with -starttls smtp, it send the STARTTLS command even if the server is to advertising the STARTTLS.
In my case the MUA (Powershell Net.Mail.SmtpClient), is throwing error "Server does not support secure connections" cause the STARTTLS command as already been used by the proxy, therefore it's not advertised by the Office365 SMTP server.
Maybe you are aware, the SMTPS (openssl s_client -connect IP_ADDRESS:465 -crlf) is not working anymore (server config with cert and key, without local_starttls = True )
Also would it be possible for the local_starttls parameter to support a way to enforce the use of STARTTLS by the MUA ?

Thanks for testing this. I've just commited a few refinements, and SMTP should now work in the following example configurations:

Local and remote STARTTLS. Test command: openssl s_client -crlf -starttls smtp -connect localhost:1587 (or an email client with STARTTLS enabled), with the following proxy configuration:

[SMTP-1587]
server_address = smtp.office365.com
server_port = 587
server_starttls = True
local_address = <IP_ADDRESS>
local_starttls = True
local_certificate_path = /path/to/ssl_cert.pem
local_key_path = /path/to/ssl_key.pem

Remote STARTTLS only; local secure connection. Test command: openssl s_client -crlf -connect localhost:1588. Proxy configuration:

[SMTP-1588]
server_address = smtp.office365.com
server_port = 587
server_starttls = True
local_address = <IP_ADDRESS>
local_certificate_path = /path/to/ssl_cert.pem
local_key_path = /path/to/ssl_key.pem

Remote STARTTLS only; unsecured local connection. Test command: telnet localhost 1589 with proxy configuration:

[SMTP-1589]
server_address = smtp.office365.com
server_port = 587
server_starttls = True
local_address = <IP_ADDRESS>

(and 5 and 6) Each of the above, but with a remote server that doesn't use STARTTLS (e.g., smtp.gmail.com on port 465), and server_starttls omitted.

Re: your other points:

But when using openssl with -starttls smtp, it send the STARTTLS command even if the server is not advertising the STARTTLS.

This is a behaviour of openssl's s_client, not the proxy. I don't know whether it can be configured to respect the advertised capabilities. I suspect not, becuse if you're using it with a non-STARTTLS server, you'd just omit the -starttls smtp.

In my case the MUA (Powershell Net.Mail.SmtpClient), is throwing error "Server does not support secure connections" cause the STARTTLS command as already been used by the proxy, therefore it's not advertised by the Office365 SMTP server.

This should work – please could you check again using the most recent version in the smtp-local-starttls branch? It's worth pointing out that the STARTTLS commands used for local and remote connections are entirely separate, so it's not possible for one to be consumed by the other.

Maybe you are aware, the SMTPS (openssl s_client -connect IP_ADDRESS:465 -crlf) is not working anymore (server config with cert and key, without local_starttls = True )

I can't reproduce this. See the [SMTP-1588] example above for a server that uses a locally-encrypted connection, but not STARTTLS.

Also would it be possible for the local_starttls parameter to support a way to enforce the use of STARTTLS by the MUA ?

The local STARTTLS feature has already been a more complex and time-consuming development commitment than I initially anticipated so this would have to be a separate feature, but I'm happy to look at it if needed.

Thanks for those updates. SMTP is working fine for plaintext, explicit TLS, and implicit TLS 🎉
Thanks very much for your work.
I have only tested it against Office365 SMTP server.
If needed, here is my config for the server part.
Support for Implicit TLS (SSL/TLS on Thunderbird) : Proxy listening on port TCP 465 on any IP of the computer running the proxy.
[SMTP-465]
server_address = smtp.office365.com
server_port = 587
server_starttls = True
local_certificate_path = smtprelay.crt
local_key_path = smtprelay.key

Support for Explicit TLS (STARTTLS on Thunderbird) and plaintext SMTP (None on Thunderbird) : Proxy listening on port TCP 587 on any IP of the computer running the proxy.
[SMTP-587]
server_address = smtp.office365.com
server_port = 587
server_starttls = True
local_starttls = True
local_certificate_path = smtprelay.crt
local_key_path = smtprelay.key

A few comments:
When the proxy is in STARTTLS/plaintext for local connection (Port 587 in the following output), in the log it says it's listening for TLS connection.
2024-03-12 21:34:22: Starting SMTP server at [::]:587 (TLS) proxying smtp.office365.com:587 (STARTTLS)
2024-03-12 21:34:22: Starting SMTP server at [::]:465 (TLS) proxying smtp.office365.com:587 (STARTTLS)

The local STARTTLS feature has already been a more complex and time-consuming development commitment than I initially anticipated so this would have to be a separate feature, but I'm happy to look at it if needed.

I understand and I'm really glad you could implement STARTTLS for local connection. It's really a game changer.
If you have time to spare on this extra feature, a way of doing it would be to check if the connection is secured (Client did send STARTTLS command), if not (client sending AUTH command in plaintext) the proxy send a TCP RST to close the connection.
Another way, would be for the proxy to send 550 5.5.1 Protocol error which is what I am seeing with public SMTP server (Port 25) for protonmail.com and posteo.net.

Great – I'm glad this is now working as intended. I've just updated the startup message, and will now merge this branch. Thanks for supporting the development of this feature!


Scala Common Enrich: make enrichments.ExtractEventTypeSpec timezone-safe

This test com.snowplowanalytics.snowplow.enrich.common.enrichments.ExtractEventTypeSpec:
[info]   This is a specification to test the extractEventType function
[info]   + extractEventType should return the event name for any valid event code
[info]   + extractEventType should return a validation failure for any invalid event code
[info]   x formatCollectorTstamp should validate collector timestamps
[error]   | SPEC NAME          | INPUT VAL                               | EXPECTED OUTPUT                                                                                |
[error] + | None               | None                                    | Failure(No collector_tstamp set)                                                                  |
[error] x | Negative timestamp | Some(-0030-01-01T02:00:00.000+01:34:52) | Failure(Collector timestamp -0030-01-01 00:00:00.000 is negative and will fail the Redshift load) | 'Failure(Collector timestamp -0030-01-01 00:25:08.000 is negative and will fail the Redshift load)'
[error]  is not equal to
[error] 'Failure(Collector timestamp -0030-01-01 00:00:00.000 is negative and will fail the Redshift load)'
[error] + | Valid timestamp    | Some(1970-01-01T02:00:00.000+02:00)     | Success(1970-01-01 00:00:00.000)                                                                  |                                                                                (eventEnrichmentSpecs.scala:71)
[error] Expected: ...1 00:[00]:0[0].000 ...
[error] Actual:   ...1 00:[25]:0[8].000 ...
[info]
[info]

fails in my timezone due to https://www.timeanddate.com/time/change/greece?year=1916
You gotta love timezones.

PR sent https://github.com/snowplow/snowplow/pull/3482

Best style for a ticket name is "Actionable command to make an objective, discrete change" hence:

Scala Common Enrich: make enrichments.ExtractEventTypeSpec timezone-safe

(The original title "enrichments.ExtractEventTypeSpec fails in my timezone" was more like a bug report.)