Compare commits

..

20 Commits
master ... eoss

Author SHA1 Message Date
TheKoola 3aee5f9f2f Update gitignore 2024-07-07 18:24:13 -06:00
TheKoola bf66acf83f Configure vscode 2024-07-07 18:23:47 -06:00
Jeff Deaton 601f71f64e Updates to the readme file to point users to documentation for building and installing the eoss branch. 2020-05-01 16:05:49 -06:00
Jeff Deaton dbb3c8c397 Updates to enable edgeofspace as the github repo 2020-05-01 15:49:48 -06:00
Jeff Deaton 161a365f39 Update startup params for the dump1090 service 2020-05-01 15:37:21 -06:00
Jeff Deaton c65472574d The data directory 2020-05-01 15:36:24 -06:00
Jeff Deaton 40897d0081 Create the json output directory if it doesn't exist 2020-05-01 15:36:24 -06:00
EOSS Tracker 5de93cd3b4 Adding the dump directory to the html folder. 2020-05-01 15:36:24 -06:00
Jeff Deaton c03bc73f4b Updates to enable and start the dump1090-fa service post install 2020-05-01 15:36:24 -06:00
Jeff Deaton 12ff4bcd80 Updates 2020-05-01 15:36:24 -06:00
Jeff Deaton b1219ee3b8 Updates to enable and start the dump1090-fa service post install 2020-05-01 15:36:24 -06:00
Jeff Deaton 50f0fc1c0a Initial changes for installation on EOSS tracker brick 2020-05-01 15:36:24 -06:00
Jeff Deaton 528bc15160 The data directory 2019-10-19 13:26:16 -06:00
Jeff Deaton aef7573a1f Merge branch 'eoss' of https://github.com/Deatojef/dump1090 into eoss 2019-10-19 13:24:46 -06:00
Jeff Deaton 72f2d41f0c Create the json output directory if it doesn't exist 2019-10-19 13:22:59 -06:00
EOSS Tracker 24f805b111 Adding the dump directory to the html folder. 2019-10-12 11:05:57 -06:00
Jeff Deaton 9b42f324b8 Updates to enable and start the dump1090-fa service post install 2019-10-07 22:00:55 -06:00
Jeff Deaton 1b264e8516 Updates 2019-10-07 21:56:40 -06:00
Jeff Deaton 504472a497 Updates to enable and start the dump1090-fa service post install 2019-10-07 21:52:50 -06:00
Jeff Deaton bdda0dfb7b Initial changes for installation on EOSS tracker brick 2019-10-06 17:28:23 -06:00
491 changed files with 4116 additions and 31141 deletions

3
.gitattributes vendored
View File

@ -1,4 +1 @@
*.xz binary *.xz binary
dsp/generated/* merge=binary linguist-generated
cpu_features/** linguist-vendored
starch/** linguist-vendored

5
.gitignore vendored
View File

@ -12,8 +12,5 @@ view1090
faup1090 faup1090
package-wheezy package-wheezy
oneoff/convert_benchmark oneoff/convert_benchmark
oneoff/uc8_capture_stats
oneoff/dsp_error_measurement
oneoff/decode_comm_b oneoff/decode_comm_b
starch-benchmark .vscode
wisdom.local

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"cmake.configureOnOpen": false
}

4
Jenkinsfile vendored
View File

@ -8,7 +8,7 @@ node(label: 'raspberrypi') {
durabilityHint(hint: 'PERFORMANCE_OPTIMIZED') durabilityHint(hint: 'PERFORMANCE_OPTIMIZED')
]) ])
def dists = ["bullseye", "buster", "stretch"] def dists = ["buster", "stretch", "jessie"]
def srcdir = "${WORKSPACE}/src" def srcdir = "${WORKSPACE}/src"
stage('Checkout') { stage('Checkout') {
@ -39,7 +39,7 @@ node(label: 'raspberrypi') {
} }
stage("Test install on ${dist}") { stage("Test install on ${dist}") {
sh "BRANCH=${env.BRANCH_NAME} /build/pi-builder/scripts/validate-packages.sh ${dist} ${results}/dump1090-fa_*.deb" sh "BRANCH=${env.BRANCH_NAME} /build/pi-builder/scripts/validate-packages.sh ${dist} ${results}/dump1090-fa_*.deb ${results}/dump1090_*.deb"
} }
} }

231
Makefile
View File

@ -1,127 +1,28 @@
PROGNAME=dump1090 PROGNAME=dump1090
DUMP1090_VERSION ?= unknown
CFLAGS ?= -O3 -g
DUMP1090_CFLAGS := -std=c11 -fno-common -Wall -Wmissing-declarations -Werror -W
DUMP1090_CPPFLAGS := -I. -D_POSIX_C_SOURCE=200112L -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
LIBS = -lpthread -lm
SDR_OBJ = cpu.o sdr.o fifo.o sdr_ifile.o dsp/helpers/tables.o
# Try to autodetect available libraries via pkg-config if no explicit setting was used
PKGCONFIG=$(shell pkg-config --version >/dev/null 2>&1 && echo "yes" || echo "no")
ifeq ($(PKGCONFIG), yes)
ifndef RTLSDR
ifdef RTLSDR_PREFIX
RTLSDR := yes
else
RTLSDR := $(shell pkg-config --exists librtlsdr && echo "yes" || echo "no")
endif
endif
ifndef BLADERF
BLADERF := $(shell pkg-config --exists libbladeRF && echo "yes" || echo "no")
endif
ifndef HACKRF
HACKRF := $(shell pkg-config --exists libhackrf && echo "yes" || echo "no")
endif
ifndef LIMESDR
LIMESDR := $(shell pkg-config --exists LimeSuite && echo "yes" || echo "no")
endif
else
# pkg-config not available. Only use explicitly enabled libraries.
RTLSDR ?= no
BLADERF ?= no
HACKRF ?= no
LIMESDR ?= no
endif
HOST_UNAME := $(shell uname)
HOST_ARCH := $(shell uname -m)
UNAME ?= $(HOST_UNAME)
ARCH ?= $(HOST_ARCH)
ifeq ($(UNAME), Linux)
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
LIBS += -lrt
LIBS_USB += -lusb-1.0
LIBS_CURSES := -lncurses
CPUFEATURES ?= yes
endif
ifeq ($(UNAME), Darwin)
ifneq ($(shell sw_vers -productVersion | egrep '^10\.([0-9]|1[01])\.'),) # Mac OS X ver <= 10.11
DUMP1090_CPPFLAGS += -DMISSING_GETTIME
COMPAT += compat/clock_gettime/clock_gettime.o
endif
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
LIBS_USB += -lusb-1.0
LIBS_CURSES := -lncurses
# cpufeatures reportedly does not work (yet) on darwin arm64
ifneq ($(ARCH),arm64)
CPUFEATURES ?= yes
endif
endif
ifeq ($(UNAME), OpenBSD)
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
LIBS_USB += -lusb-1.0
LIBS_CURSES := -lncurses
endif
ifeq ($(UNAME), FreeBSD)
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
LIBS += -lrt
LIBS_USB += -lusb
LIBS_CURSES := -lncurses
endif
ifeq ($(UNAME), NetBSD)
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
LIBS += -lrt
LIBS_USB += -lusb-1.0
LIBS_CURSES := -lcurses
endif
CPUFEATURES ?= no
ifeq ($(CPUFEATURES),yes)
include Makefile.cpufeatures
DUMP1090_CPPFLAGS += -DENABLE_CPUFEATURES -Icpu_features/include
endif
RTLSDR ?= yes RTLSDR ?= yes
BLADERF ?= yes BLADERF ?= yes
CPPFLAGS += -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
DIALECT = -std=c11
CFLAGS += $(DIALECT) -O2 -g -Wall -Werror -W -D_DEFAULT_SOURCE
LIBS = -lpthread -lm -lrt
ifeq ($(RTLSDR), yes) ifeq ($(RTLSDR), yes)
SDR_OBJ += sdr_rtlsdr.o SDR_OBJ += sdr_rtlsdr.o
DUMP1090_CPPFLAGS += -DENABLE_RTLSDR CPPFLAGS += -DENABLE_RTLSDR
ifdef RTLSDR_PREFIX ifdef RTLSDR_PREFIX
DUMP1090_CPPFLAGS += -I$(RTLSDR_PREFIX)/include CPPFLAGS += -I$(RTLSDR_PREFIX)/include
ifeq ($(STATIC), yes) ifeq ($(STATIC), yes)
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic $(LIBS_USB) LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic -lusb-1.0
else else
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -lrtlsdr $(LIBS_USB) LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -lrtlsdr -lusb-1.0
endif endif
else else
CFLAGS += $(shell pkg-config --cflags librtlsdr)
# some packaged .pc files are massively broken, try to handle it # some packaged .pc files are massively broken, try to handle it
# FreeBSD's librtlsdr.pc includes -std=gnu89 in cflags
# some linux librtlsdr packages return a bare -I/ with no path in --cflags
RTLSDR_CFLAGS := $(shell pkg-config --cflags librtlsdr)
RTLSDR_CFLAGS := $(filter-out -std=%,$(RTLSDR_CFLAGS))
RTLSDR_CFLAGS := $(filter-out -I/,$(RTLSDR_CFLAGS))
DUMP1090_CFLAGS += $(RTLSDR_CFLAGS)
# some linux librtlsdr packages return a bare -L with no path in --libs
# which horribly confuses things because it eats the next option on the command line
RTLSDR_LFLAGS := $(shell pkg-config --libs-only-L librtlsdr) RTLSDR_LFLAGS := $(shell pkg-config --libs-only-L librtlsdr)
ifeq ($(RTLSDR_LFLAGS),-L) ifeq ($(RTLSDR_LFLAGS),-L)
LIBS_SDR += $(shell pkg-config --libs-only-l --libs-only-other librtlsdr) LIBS_SDR += $(shell pkg-config --libs-only-l --libs-only-other librtlsdr)
@ -133,118 +34,42 @@ endif
ifeq ($(BLADERF), yes) ifeq ($(BLADERF), yes)
SDR_OBJ += sdr_bladerf.o SDR_OBJ += sdr_bladerf.o
DUMP1090_CPPFLAGS += -DENABLE_BLADERF CPPFLAGS += -DENABLE_BLADERF
DUMP1090_CFLAGS += $(shell pkg-config --cflags libbladeRF) CFLAGS += $(shell pkg-config --cflags libbladeRF)
LIBS_SDR += $(shell pkg-config --libs libbladeRF) LIBS_SDR += $(shell pkg-config --libs libbladeRF)
endif endif
ifeq ($(HACKRF), yes) all: dump1090 view1090
SDR_OBJ += sdr_hackrf.o
DUMP1090_CPPFLAGS += -DENABLE_HACKRF
DUMP1090_CFLAGS += $(shell pkg-config --cflags libhackrf)
LIBS_SDR += $(shell pkg-config --libs libhackrf)
endif
ifeq ($(LIMESDR), yes)
SDR_OBJ += sdr_limesdr.o
DUMP1090_CPPFLAGS += -DENABLE_LIMESDR
DUMP1090_CFLAGS += $(shell pkg-config --cflags LimeSuite)
LIBS_SDR += $(shell pkg-config --libs LimeSuite)
endif
##
## starch (runtime DSP code selection) mix, architecture-specific
##
ifneq ($(CPUFEATURES),yes)
# need to be able to detect CPU features at runtime to enable any non-standard compiler flags
STARCH_MIX := generic
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
else
ifeq ($(ARCH),x86_64)
# AVX, AVX2
STARCH_MIX := x86
DUMP1090_CPPFLAGS += -DSTARCH_MIX_X86
else ifeq ($(findstring aarch,$(ARCH)),aarch)
STARCH_MIX := aarch64
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
else ifeq ($(findstring arm64,$(ARCH)),arm64)
# Apple calls this arm64, not aarch64
STARCH_MIX := aarch64
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
else ifeq ($(findstring arm,$(ARCH)),arm)
# ARMv7 NEON
STARCH_MIX := arm
DUMP1090_CPPFLAGS += -DSTARCH_MIX_ARM
else
STARCH_MIX := generic
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
endif
endif
all: showconfig dump1090 view1090 starch-benchmark
ALL_CCFLAGS := $(CPPFLAGS) $(DUMP1090_CPPFLAGS) $(CFLAGS) $(DUMP1090_CFLAGS)
STARCH_COMPILE := $(CC) $(ALL_CCFLAGS) -c
include dsp/generated/makefile.$(STARCH_MIX)
showconfig:
@echo "Building with:" >&2
@echo " Version string: $(DUMP1090_VERSION)" >&2
@echo " Architecture: $(ARCH)" >&2
@echo " DSP mix: $(STARCH_MIX)" >&2
@echo " RTLSDR support: $(RTLSDR)" >&2
@echo " BladeRF support: $(BLADERF)" >&2
@echo " HackRF support: $(HACKRF)" >&2
@echo " LimeSDR support: $(LIMESDR)" >&2
%.o: %.c *.h %.o: %.c *.h
$(CC) $(ALL_CCFLAGS) -c $< -o $@ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o ais_charset.o adaptive.o $(SDR_OBJ) $(COMPAT) $(CPUFEATURES_OBJS) $(STARCH_OBJS) dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o sdr_ifile.o sdr.o ais_charset.o $(SDR_OBJ) $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) $(LIBS_CURSES) $(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) -lncurses
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT) view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_CURSES) $(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) -lncurses
faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT) faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
starch-benchmark: cpu.o dsp/helpers/tables.o $(CPUFEATURES_OBJS) $(STARCH_OBJS) $(STARCH_BENCHMARK_OBJ)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
clean: clean:
rm -f *.o oneoff/*.o compat/clock_gettime/*.o compat/clock_nanosleep/*.o cpu_features/src/*.o dsp/generated/*.o dsp/helpers/*.o $(CPUFEATURES_OBJS) dump1090 view1090 faup1090 cprtests crctests oneoff/convert_benchmark oneoff/decode_comm_b oneoff/dsp_error_measurement oneoff/uc8_capture_stats starch-benchmark rm -f *.o compat/clock_gettime/*.o compat/clock_nanosleep/*.o dump1090 view1090 faup1090 cprtests crctests convert_benchmark
test: cprtests test: cprtests
./cprtests ./cprtests
cprtests: cpr.o cprtests.o cprtests: cpr.o cprtests.o
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm $(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
crctests: crc.c crc.h crctests: crc.c crc.h
$(CC) $(ALL_CCFLAGS) -g -DCRCDEBUG -o $@ $< $(CC) $(CPPFLAGS) $(CFLAGS) -g -DCRCDEBUG -o $@ $<
benchmarks: oneoff/convert_benchmark benchmarks: convert_benchmark
oneoff/convert_benchmark ./convert_benchmark
oneoff/convert_benchmark: oneoff/convert_benchmark.o convert.o util.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS) oneoff/convert_benchmark: oneoff/convert_benchmark.o convert.o util.o
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm -lpthread $(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
oneoff/decode_comm_b: oneoff/decode_comm_b.o comm_b.o ais_charset.o oneoff/decode_comm_b: oneoff/decode_comm_b.o comm_b.o ais_charset.o
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm $(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
oneoff/dsp_error_measurement: oneoff/dsp_error_measurement.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
oneoff/uc8_capture_stats: oneoff/uc8_capture_stats.o
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
starchgen:
dsp/starchgen.py .
.PHONY: wisdom.local
wisdom.local: starch-benchmark
./starch-benchmark -i 5 -o wisdom.local mean_power_u16 mean_power_u16_aligned magnitude_uc8 magnitude_uc8_aligned
./starch-benchmark -i 5 -r wisdom.local -o wisdom.local

View File

@ -1,38 +0,0 @@
# -*- makefile -*-
# cmake integration is a little tricky, so let's do this by hand for now
CPUFEATURES_UNAME ?= $(UNAME)
CPUFEATURES_ARCH ?= $(ARCH)
CPUFEATURES_CFLAGS ?= $(CFLAGS)
CPUFEATURES_OBJS := cpu_features/src/filesystem.o cpu_features/src/stack_line_reader.o cpu_features/src/string_view.o
CPUFEATURES_EXTRA_CFLAGS := -std=c99
CPUFEATURES_EXTRA_CPPFLAGS := -DSTACK_LINE_READER_BUFFER_SIZE=1024 -DNDEBUG -Icpu_features/include
ifeq ($(CPUFEATURES_UNAME),Linux)
CPUFEATURES_OBJS += cpu_features/src/hwcaps.o
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_STRONG_GETAUXVAL
endif
ifeq ($(CPUFEATURES_UNAME),Darwin)
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_SYSCTLBYNAME
endif
ifeq ($(CPUFEATURES_ARCH),x86_64)
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
endif
ifneq (,$(filter i%86,$(CPUFEATURES_ARCH)))
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
endif
ifneq (,$(findstring arm,$(CPUFEATURES_ARCH)))
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_arm.o
endif
ifneq (,$(findstring aarch64,$(CPUFEATURES_ARCH)))
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_aarch64.o
endif
$(CPUFEATURES_OBJS): override ALL_CCFLAGS := $(CPUFEATURES_CPPFLAGS) $(CPUFEATURES_EXTRA_CPPFLAGS) $(CPUFEATURES_CFLAGS) $(CPUFEATURES_EXTRA_CFLAGS)

View File

@ -7,15 +7,15 @@ about dump1090's operation to collectd for later graphing.
## Reading the json files ## Reading the json files
dump1090-fa writes json files periodically to the location specified by the `--write-json` command line option. There are two ways to obtain the json files:
These json files can then be exposed via a separate standalone webserver e.g. lighttpd.
The files are written periodically; for aircraft, typically once a second, for stats, once a minute. * By HTTP from dump1090's internal webserver, which defaults to running on port 8080. The json is served from the data/ path, e.g. http://somehost:8080/data/aircraft.json
The interval between file updates can be controlled by the `--write-json-every` and `--json-stats-every` options. * As a file in the directory specified by --write-json on dump1090's command line. These can be exposed via a
As these files are frequently updated, it's a good idea to put them in RAM rather than on disk. Package installs separate webserver.
default to putting the file under `/run`, which is in RAM.
New versions of each file are written to a temporary file, then atomically renamed to the right path, so you should never see partial copies. The HTTP versions are always up to date.
The file versions are written periodically; for aircraft, typically once a second, for stats, once a minute.
The file versions are updated to a temporary file, then atomically renamed to the right path, so you should never see partial copies.
Each file contains a single JSON object. The file formats are: Each file contains a single JSON object. The file formats are:
@ -81,8 +81,6 @@ This file contains dump1090's list of recently seen aircraft. The keys are:
* sil_type: interpretation of SIL: unknown, perhour, persample * sil_type: interpretation of SIL: unknown, perhour, persample
* gva: Geometric Vertical Accuracy (2.2.3.2.7.2.8) * gva: Geometric Vertical Accuracy (2.2.3.2.7.2.8)
* sda: System Design Assurance (2.2.3.2.7.2.4.6) * sda: System Design Assurance (2.2.3.2.7.2.4.6)
* modea: true if we seem to be also receiving Mode A responses from this aircraft
* modec: true if we seem to be also receiving Mode C responses from this aircraft
* mlat: list of fields derived from MLAT data * mlat: list of fields derived from MLAT data
* tisb: list of fields derived from TIS-B data * tisb: list of fields derived from TIS-B data
* messages: total number of Mode S messages received from this aircraft * messages: total number of Mode S messages received from this aircraft
@ -164,4 +162,3 @@ Each period has the following subkeys:
* all: total tracks created * all: total tracks created
* single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address. * single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address.
* messages: total number of messages accepted by dump1090 from any source * messages: total number of messages accepted by dump1090 from any source
* messages_by_df: an array of integers where entry N (0..31) is the total number of messages accepted with downlink format (DF) = N.

View File

@ -1,191 +0,0 @@
# Adaptive gain configuration
dump1090-fa can optionally tune the receiver gain automatically to try to
pick a gain value for the particular hardware and RF environment without
manual tuning. This README covers some of the background for why this is
useful, and how to configure dump1090 to enable this feature.
## Background
In general, more receiver gain means better reception. Most ADS-B transmitters
within line of sight transmit with enough power that their messages can
potentially be decoded, but if the receiver gain setting is too low then very
weak signals may still be too weak to be decoded even after amplification.
Adding extra receiver gain helps in this case.
However, there are two problems with just adding more gain to a wideband SDR.
First, _everything_ is amplified, not only the signals of interest. Noise and
RF interference is also amplified. At high gain settings or in noisy RF
environments, this can interfere with receiving the ADS-B signals themselves.
Second, there is a wide range of possible ADS-B signal strengths. There can be
a 60dB or more difference between the weakest signals (a distant aircraft at
the limit of receiver range) and the strongest signals (a nearby aircraft on
the ramp 100m from the receiver). Increasing the receiver gain to handle the
weakest signals can mean that the strongest signals overload the receiver.
A rtlsdr receiver only has about 30-35dB of dynamic range available at a
particular gain setting, so there is no single gain setting that can
simultaneously handle both the weakest and strongest signals.
Adaptive gain tries to deal with these cases by changing the receiver gain
on the fly to handle the signal and noise levels that are currently being seen
without human intervention. It is not perfect and it's not a substitute for
hand-tuning of gain settings, but it aims at picking a reasonable setting for
cases where individual hand-tuning isn't possible.
## Where to configure adaptive gain options
How to configure adaptive gain varies depending on how you have installed
dump1090.
If you are using a PiAware sdcard image, adaptive gain can be configured by
editing `/boot/piaware-config.txt` or by using the `piaware-config` command.
If you are using the Debian package, adaptive gain can be configured by editing
`/etc/default/dump1090-fa`.
If running dump1090 directly, adaptive gain options are set directly by
command-line options.
## Default settings
For new PiAware or Debian package installations, adaptive dynamic range mode
is enabled by default and adaptive burst mode is disabled by default.
For _upgrades_ of PiAware or the Debian package from versions older than 6.0,
both adaptive gain modes are disabled by default.
These defaults can be overridden as described below.
## Adaptive gain in dynamic range mode
The dynamic range adaptive gain mode attempts to set the receiver gain to
maintain a given dynamic range - that is, it tries to set the gain so that
general noise is at or below a given level. This takes into account different
or changing RF environments and different receiver hardware (antenna,
preamplifiers, etc) that affects the overall gain of the system, and usually
will pick a reasonable gain setting without intervention.
To enable this mode:
* Set `adaptive-dynamic-range yes` in piaware-config; or
* Set `ADAPTIVE_DYNAMIC_RANGE=yes` in `/etc/default/dump1090-fa`; or
* Pass the `--adaptive-range` option on the command line.
The default settings for dynamic range will use a dynamic range target chosen
based on SDR type (e.g. 30dB for rtlsdr receivers). This is usually a good
default. To override this target:
* Set `adaptive-dynamic-range-target` in piaware-config; or
* Set `ADAPTIVE_DYNAMIC_RANGE_TARGET` in `/etc/default/dump1090-fa`; or
* Pass the `--adaptive-range-target` option on the command line.
## Adaptive gain in "burst" / loud signal mode
The "burst" adaptive gain mode listens for loud bursts of signal that were
_not_ successfully decoded as ADS-B messages, but which have approximately
the right timing to be possible messages that were lost due to receiver
overloading. When enough overly-loud signals are heard in a short period of
time, dump1090 will _reduce_ the receiver gain to try to allow them to be
received.
This is a more situational setting. It may allow reception of loud nearby
aircraft (e.g. if you are close to an airport). The tradeoff is that when
there are nearby aircraft, overall receiver range may be reduced. Whether
this is a good tradeoff depends on the aircraft you're interested in.
By default, adaptive gain burst mode is disabled.
To enable burst mode:
* Set `adaptive-burst yes` in piaware-config; or
* Set `ADAPTIVE_BURST=yes` in `/etc/default/dump1090-fa`; or
* Pass the `--adaptive-burst` option on the command line.
This mode is more experimental than the dynamic range mode and tweaking of
the advanced burst options may be needed depending on your local installation.
In particular, `--adaptive-burst-loud-rate` and `adaptive-burst-quiet-rate`
may need adjusting. Feedback on what works for you and what doesn't would
be appreciated!
Burst mode and dynamic range mode can be enabled at the same time.
## Limiting the gain range
If you know in advance approximately what the gain setting should be, so
you want to allow adaptive gain to change the gain only within a certain range,
you can set minimum and maximum gain settings in dB. Adaptive gain will only
adjust the gain within this range. To set this:
* Set `adaptive-min-gain` and `adaptive-max-gain` in piaware-config; or
* Set `ADAPTIVE_MIN_GAIN` and `ADAPTIVE_MAX_GAIN` in `/etc/default/dump1090-fa`; or
* Pass the `--adaptive-min-gain` and `--adaptive-max-gain` options on the command line.
If you know approximately where the gain should be, then a good starting point would be
to set the max and min adaptive gain to +/- 10dB around your gain setting.
## Reducing the CPU cost of adaptive gain
The measurements needed to adjust gain have a CPU cost, and on slower
devices it may be useful to reduce the amount of work that adaptive gain does.
This can be done by adjusting the adaptive gain duty cycle. This is a
percentage that controls what fraction of incoming data adaptive gain inspects.
100% means that every sample is inspected. Lower values reduce CPU use, with
a tradeoff that adaptive gain has a less accurate picture of the RF
environment. The default duty cycle is 50% on "fast" CPUs and 10% on "slow"
CPUs (where currently "slow" means "armv6 architecture", for example the
Pi Zero or Pi 1). To reduce the duty cycle further:
* Set `slow-cpu yes` in piaware-config; or
* Set `SLOW_CPU=yes` in `/etc/default/dump1090-fa`; or
* Pass the `--adaptive-duty-cycle` option on the command line
## Advanced options
There are a number of advanced options that are only supported as
command-line options or via the EXTRA_OPTIONS setting in
`/etc/default/dump1090-fa`. They tweak settings that require some knowledge of
dump1090 internals to make sense of, so YMMV.
For a complete list of options, run `dump1090-fa --help` and look at the
adaptive gain section.
## Device support
Currently, adaptive gain is only supported on rtlsdr devices. Support for other
SDRs is planned for the future.
If you're a developer and want to add support for your SDR, you'll need
to implement the gain control API used in `sdr.[ch]`. See `sdr_rtlsdr.c`
(`rtlsdrGetGain`, `rtlsdrSetGain`, etc) for examples.
## Comparison with wiedehopf's auto-gain scripts
There is an [auto-gain script](https://github.com/wiedehopf/adsb-scripts/wiki/Automatic-gain-optimization-for-readsb-and-dump1090-fa)
written by [wiedehopf](https://github.com/wiedehopf) that aims to solve similar
problems. The implementation approaches are quite different, and which one works best
for you will depend on the problem you're trying to solve.
The major differences between adaptive gain and the auto-gain script are:
* Adaptive gain works on short-term data (seconds or minutes) and can react to
changes in a similar timeframe. It tries to set an appropriate gain for the
_current_ environment without much regard for longer-term trends. The auto-gain
script looks at data over longer timeframes (1+ days) and reacts more slowly,
but takes into account data across that whole period.
* Adaptive gain in dynamic range mode looks at an estimate of the noise floor
to decide whether to increase gain. Adaptive gain in burst mode looks at the
signal strength of samples that were _not_ successfully decoded to decide when
to reduce gain. The auto-gain scripts look at the signal strength of _successfully_
decoded messages to decide when to increase or decrease gain. These are each measuring
something different, and which is most effective will depend on the exact RF
environment.
* Adaptive gain burst mode and the auto-gain script superfically measure similar things,
but the difference in measurement timeframe mean they react quite differently. Burst mode
tries to react to transient loud signals i.e. temporarily nearby aircraft. The auto-gain
script uses the loud-messages fraction as an estimate for messages lost to excessive
gain over the long term, not only the transient case.
* Adaptive gain has a few less moving parts (i.e. no external scripts, no config changes over
time) as it's built directly into dump1090 itself.

144
README.md
View File

@ -1,48 +1,64 @@
# EOSS Specific Changes
The `eoss` branch adds the following changes/features so that the dump1090-fa release can work relatively seamlessly on the EOSS SDR system:
- Updates to the web display and the underlying Javascript to Redirect the map source to the locally running OSM map server. This way map tiles are fetched from the local system and removes the need for a dedicated Internet connection.
- Apache is used as the web server of choice instead of lighttpd. The Apache configuration is modified to use an alias (/dump1090-fa) pointing to the /user/share/dump1090-fa/html directory.
- Parameter changes for the dump1090-fa daemon so that it looks to use only those RTL-SDR USB dongles that have been labeled with "ADSB" as their serial number. This allows
multiple RTL-SDR dongles to be used on the SDR system (dump1090-fa uses one while the SDR system can use another).
For detailed instructions and build info for the `eoss` branch, please see the [EOSS-Install-dump1090](https://github.com/TheKoola/eosstracker/blob/master/doc/EOSS-Install-dump1090.md) under the eosstracker project.
# dump1090-fa Debian/Raspbian packages # dump1090-fa Debian/Raspbian packages
dump1090-fa is a ADS-B, Mode S, and Mode 3A/3C demodulator and decoder that This is a fork of [dump1090-mutability](https://github.com/mutability/dump1090)
will receive and decode aircraft transponder messages received via customized for use within [FlightAware](http://flightaware.com)'s
a directly connected software defined radio, or from data provided over a [PiAware](http://flightaware.com/adsb/piaware) software.
network connection.
It is the successor to It is designed to build as a Debian package.
[dump1090-mutability](https://github.com/mutability/dump1090) and is
maintained by [FlightAware](http://flightaware.com/).
It can provide a display of locally received aircraft data in a terminal or ## Building under stretch
via a browser map. Together with [PiAware](http://flightaware.com/adsb/piaware)
it can be used to contribute crowd-sourced flight tracking data to FlightAware.
It is designed to build as a Debian package, but should also be buildable on
many other Linux or Unix-like systems.
## Building under bullseye, buster, or stretch
```bash ```bash
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev $ sudo apt-get install build-essential debhelper librtlsdr-dev pkg-config dh-systemd libncurses5-dev libbladerf-dev
$ ./prepare-build.sh bullseye # or buster, or stretch $ dpkg-buildpackage -b
$ cd package-bullseye # or buster, or stretch
$ dpkg-buildpackage -b --no-sign
``` ```
## Building with limited dependencies ## Building under jessie
(Supported for bullseye and buster builds only) ### Dependencies - bladeRF
The package supports some build profiles to allow building without all You will need a build of libbladeRF. You can build packages from source:
required SDR libraries being present. This will produce a package with
limited SDR support only.
Pass `--build-profiles` to `dpkg-buildpackage` with a comma-separated list of
profiles. The list of profiles should include `custom` and zero or more of
`rtlsdr`, `bladerf`, `hackrf`, `limesdr` depending on what you want:
```bash ```bash
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr # builds with rtlsdr support only $ git clone https://github.com/Nuand/bladeRF.git
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr,bladerf # builds with rtlsdr and bladeRF support $ cd bladeRF
$ dpkg-buildpackage -b --no-sign --build-profiles=custom # builds with _no_ SDR support (network support only) $ git checkout 2017.12-rc1
$ dpkg-buildpackage -b
``` ```
Or Nuand has some build/install instructions including an Ubuntu PPA
at https://github.com/Nuand/bladeRF/wiki/Getting-Started:-Linux
Or FlightAware provides armhf packages as part of the piaware repository;
see https://flightaware.com/adsb/piaware/install
### Dependencies - rtlsdr
This is packaged with jessie. `sudo apt-get install librtlsdr-dev`
### Actually building it
Nothing special, just build it (`dpkg-buildpackage -b`)
## Building under wheezy
First run `prepare-wheezy-tree.sh`. This will create a package tree in
package-wheezy/. Build in there (`dpkg-buildpackage -b`)
The wheezy build does not include bladeRF support.
## Building manually ## Building manually
You can probably just run "make" after installing the required dependencies. You can probably just run "make" after installing the required dependencies.
@ -54,69 +70,3 @@ libbladeRF.
``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on ``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on
librtlsdr. librtlsdr.
``make HACKRF=no`` will disable HackRF support and remove the dependency on
libhackrf.
``make LIMESDR=no`` will disable LimeSDR support and remove the dependency on
libLimeSuite.
## Building on OSX
Minimal testing on Mojave 10.14.6, YMMV.
```
$ brew install librtlsdr
$ brew install libbladerf
$ brew install hackrf
$ brew install pkg-config
$ make
```
## Building on FreeBSD
Minimal testing on 12.1-RELEASE, YMMV.
```
# pkg install gmake
# pkg install pkgconf
# pkg install rtl-sdr
# pkg install bladerf
# pkg install hackrf
$ gmake
```
## Generating wisdom files
dump1090-fa uses [starch](https://github.com/flightaware/starch) to build
multiple versions of the DSP code and choose the fastest supported by the
hardware at runtime. The implementations chosen can been seen by running
`dump1090-fa --version`.
The implementations used are controlled by "wisdom files", a list of
implementations to use in order of priority. For each DSP function, the first
implementation listed that's supported by the current hardware is used.
By default dump1090-fa provides compiled-in wisdom for [x86](wisdom.x86),
[ARM 32-bit](wisdom.arm), and [ARM 64-bit](wisdom.aarch64). If the defaults
are not suitable for your hardware or if you're building on a different
architecture, you may want to generate your own external wisdom file.
Ideally, to get stable results, you want to do this on an idle system
with CPU frequency scaling disabled. Running the benchmarks will take
some time (10s of minutes).
### Package installs
Run `/usr/share/dump1090-fa/generate-wisdom`. Wait.
Follow the instructions to copy the resulting wisdom file to `/etc/dump1090-fa/wisdom.local`.
Restart dump1090.
### Manual installs
Run `make wisdom.local`. Wait.
Copy the resulting `wisdom.local` file somewhere appropriate.
Update the dump1090-fa command-line options to include `--wisdom /path/to/wisdom.local`

View File

@ -1,645 +0,0 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// adaptive.c: adaptive gain control
//
// Copyright (c) 2021 FlightAware, LLC
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dump1090.h"
#include "adaptive.h"
//
// gain limits
//
static int adaptive_gain_min;
static int adaptive_gain_max;
// gain steps relative to current gain
static float adaptive_gain_up_db;
static float adaptive_gain_down_db;
//
// block handling
//
// 1 block = approx 1 second of samples. Control updates are done at the end of each block only.
// Each block is made up of an integer number of subblocks (currently 20)
//
// 1 subblock = approx 50ms of samples. Duty cycle decisions are made at the subblock level;
// either the whole subblock is processed, or the whole subblock is skipped.
// Each subblock is made up of an integer number of windows (currently 1250)
//
// 1 window = approx 40us of samples. Burst measurements are made by counting samples within each window.
//
// All three levels are aligned, i.e. every block boundary is also a subblock boundary;
// every subblock boundary is also a window boundary.
static const unsigned adaptive_subblocks_per_block = 20; // subblocks per block
static unsigned adaptive_subblocks_remaining; // subblocks remaining in the current block
// Duty cycle is expressed as N/D
// where N = adaptive_subblbock_dutycycle_N = adaptive_subblocks_per_block * Modes.adaptive_duty_cycle
// and D = adaptive_subblocks_dutycycle_D = adaptive_subblocks_per_block
//
// i.e. within each block, there are exactly N active subblocks out of D total subblocks
//
// The active subblocks are distributed evenly across the block by increasing a counter by N on each
// subblock, modulo D, and marking the subblock as active each time the counter rolls over.
static unsigned adaptive_subblock_dutycycle_N; // subblock duty cycle numerator N
// stretch gcc doesn't like this as a separate const
#define adaptive_subblock_dutycycle_D adaptive_subblocks_per_block
static unsigned adaptive_subblock_dutycycle_counter; // subblock duty cycle counter (modulo D)
static bool adaptive_subblock_active; // is the current subblock active i.e. samples should be processed, not skipped?
static unsigned adaptive_samples_per_subblock; // samples per subblock
static unsigned adaptive_subblock_samples_remaining; // samples remaining in the current subblock
static unsigned adaptive_samples_per_window; // samples per window
void adaptive_init();
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded);
static void adaptive_end_of_block();
static void adaptive_control_update();
//
// burst handling
//
static unsigned adaptive_burst_window_remaining; // samples remaining in the current burst window
static unsigned adaptive_burst_window_counter; // loud samples seen in current burst window
static unsigned adaptive_burst_runlength; // consecutive loud burst windows seen
static unsigned adaptive_burst_block_loud_undecoded; // loud undecoded bursts seen in this block so far
static unsigned adaptive_burst_block_loud_decoded; // loud decoded messages seen in this block so far
static double adaptive_burst_loud_undecoded_smoothed; // smoothed rate of loud misdecodes per block
static double adaptive_burst_loud_decoded_smoothed; // smoothed rate of loud successful decodes per block
static unsigned adaptive_burst_change_timer; // countdown inhibiting control after changing gain
static double adaptive_burst_loud_threshold; // current signal level threshold for a "loud decode"
static unsigned adaptive_burst_loud_blocks = 0; // consecutive blocks with loud rate
static unsigned adaptive_burst_quiet_blocks = 0; // consecutive blocks with quiet rate
static void adaptive_burst_update(uint16_t *buf, unsigned length);
static void adaptive_burst_skip(unsigned length);
static unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n);
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows);
static void adaptive_burst_end_of_window(unsigned counter);
static void adaptive_burst_end_of_block();
//
// noise floor measurement (adaptive dynamic range)
//
static unsigned *adaptive_range_radix; // radix-sort buckets for current block
static unsigned adaptive_range_radix_counter; // sum of all radix-sort buckets (= number of samples sorted)
static double adaptive_range_smoothed; // smoothed noise floor estimate, dBFS
static enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN, RANGE_RESCAN_UP, RANGE_RESCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP;
static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain
static unsigned adaptive_range_rescan_timer; // countdown to next upwards gain reprobe
static int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range
static void adaptive_range_update(uint16_t *buf, unsigned length);
static void adaptive_range_end_of_block();
// Try to change the SDR gain to 'step' and tell the user about it,
// with 'why' as the reason to show. Return true if the gain actually changed.
static bool adaptive_set_gain(int step, const char *why)
{
if (step < adaptive_gain_min)
step = adaptive_gain_min;
if (step > adaptive_gain_max)
step = adaptive_gain_max;
int current_gain = sdrGetGain();
if (current_gain == step)
return false;
fprintf(stderr, "adaptive: changing gain from %.1fdB (step %d) to %.1fdB (step %d) because: %s\n",
sdrGetGainDb(current_gain), current_gain, sdrGetGainDb(step), step, why);
int new_gain = sdrSetGain(step);
bool changed = (current_gain != new_gain);
if (changed)
++Modes.stats_current.adaptive_gain_changes;
return changed;
}
// Update internal state to reflect a gain change
// (usually after adaptive_set_gain returns true, but also called during init)
static void adaptive_gain_changed()
{
int new_gain = sdrGetGain();
adaptive_gain_up_db = sdrGetGainDb(new_gain + 1) - sdrGetGainDb(new_gain);
adaptive_gain_down_db = sdrGetGainDb(new_gain) - sdrGetGainDb(new_gain - 1);
double loud_threshold_dbfs = 0 - adaptive_gain_up_db - 3.0;
adaptive_burst_loud_threshold = pow(10, loud_threshold_dbfs / 10.0);
adaptive_range_change_timer = Modes.adaptive_range_change_delay;
adaptive_burst_change_timer = Modes.adaptive_burst_change_delay;
adaptive_burst_loud_blocks = 0;
adaptive_burst_quiet_blocks = 0;
}
// External init entry point
void adaptive_init()
{
int maxgain = sdrGetMaxGain();
// If the SDR doesn't support gain control, disable ourselves
if (maxgain < 0) {
if (Modes.adaptive_burst_control || Modes.adaptive_range_control) {
fprintf(stderr, "warning: adaptive gain control requested, but SDR gain control not available, ignored.\n");
}
Modes.adaptive_burst_control = false;
Modes.adaptive_range_control = false;
}
// If we're disabled, do nothing
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
return;
// Set up window, subblock, and block sizes
// Look for 40us bursts
adaptive_samples_per_window = Modes.sample_rate / 25000;
// Use ~50ms subblocks; ensure it's an exact multiple of window size
adaptive_samples_per_subblock = adaptive_samples_per_window * 1250;
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
adaptive_subblock_active = false;
float N = roundf(adaptive_subblock_dutycycle_D * Modes.adaptive_duty_cycle);
if (N <= 0)
N = 1;
if (N > adaptive_subblock_dutycycle_D)
N = adaptive_subblock_dutycycle_D;
fprintf(stderr, "adaptive: using %.0f%% duty cycle\n", 100.0 * N / adaptive_subblock_dutycycle_D);
adaptive_subblock_dutycycle_N = (unsigned)N;
adaptive_burst_window_remaining = adaptive_samples_per_window;
adaptive_burst_window_counter = 0;
adaptive_range_radix = calloc(sizeof(unsigned), 65536);
adaptive_range_state = RANGE_RESCAN_UP;
// select and enforce gain limits
for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) {
if (sdrGetGainDb(adaptive_gain_min) >= Modes.adaptive_min_gain_db)
break;
}
for (adaptive_gain_max = maxgain; adaptive_gain_max > adaptive_gain_min; --adaptive_gain_max) {
if (sdrGetGainDb(adaptive_gain_max) <= Modes.adaptive_max_gain_db)
break;
}
fprintf(stderr, "adaptive: enabled adaptive gain control with gain limits %.1fdB (step %d) .. %.1fdB (step %d)\n",
sdrGetGainDb(adaptive_gain_min), adaptive_gain_min, sdrGetGainDb(adaptive_gain_max), adaptive_gain_max);
if (Modes.adaptive_range_control)
fprintf(stderr, "adaptive: enabled dynamic range control, target dynamic range %.1fdB\n", Modes.adaptive_range_target);
if (Modes.adaptive_burst_control)
fprintf(stderr, "adaptive: enabled burst control\n");
adaptive_set_gain(sdrGetGain(), "constraining gain to adaptive gain limits");
adaptive_gain_changed();
adaptive_range_gain_limit = sdrGetGain();
}
// Feed some samples into the adaptive system. Any number of samples might be passed in.
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded)
{
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
return;
// process complete subblocks
while (length >= adaptive_subblock_samples_remaining) {
if (adaptive_subblock_active)
adaptive_update_subblock(buf, adaptive_subblock_samples_remaining, decoded);
buf += adaptive_subblock_samples_remaining;
length -= adaptive_subblock_samples_remaining;
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
adaptive_subblock_dutycycle_counter += adaptive_subblock_dutycycle_N;
if (adaptive_subblock_dutycycle_counter >= adaptive_subblock_dutycycle_D) {
adaptive_subblock_dutycycle_counter -= adaptive_subblock_dutycycle_D;
adaptive_subblock_active = true;
} else {
adaptive_subblock_active = false;
// fake a quiet window to reset any existing run
adaptive_burst_end_of_window(0);
}
if (!--adaptive_subblocks_remaining) {
// Block completed, do a control update
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
adaptive_end_of_block();
}
}
// process final samples that don't complete a subblock
if (length > 0) {
if (adaptive_subblock_active)
adaptive_update_subblock(buf, length, decoded);
adaptive_subblock_samples_remaining -= length;
}
}
// Feed some samples into the adaptive system. The samples are guaranteed to not cross a subblock boundary.
// The samples should be processsed (i.e. duty cycle is in the active part)
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded)
{
if (decoded) {
if (/* decoded->msgbits == 112 && */ decoded->signalLevel >= adaptive_burst_loud_threshold)
++adaptive_burst_block_loud_decoded;
adaptive_burst_skip(length);
} else {
adaptive_burst_update(buf, length);
adaptive_range_update(buf, length);
}
}
// Burst measurement: ignore the next 'length' samples (they are a successfully decoded message)
static void adaptive_burst_skip(unsigned length)
{
if (!Modes.adaptive_burst_control)
return;
// first window
if (length < adaptive_burst_window_remaining) {
// partial fill
adaptive_burst_window_remaining -= length;
return;
}
// skip remainder of first window, dispatch it
adaptive_burst_end_of_window(adaptive_burst_window_counter);
length -= adaptive_burst_window_remaining;
// skip remaining windows, dispatch them
unsigned windows = length / adaptive_samples_per_window;
unsigned samples = windows * adaptive_samples_per_window;
while (windows--)
adaptive_burst_end_of_window(0);
length -= samples;
// final partial window
adaptive_burst_window_counter = 0;
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
}
// Burst measurement: process 'length' samples from 'buf', look for loud bursts;
// the samples might cross burst window boundaries;
// the samples will not cross a block boundary.
static void adaptive_burst_update(uint16_t *buf, unsigned length)
{
if (!Modes.adaptive_burst_control)
return;
// first window
if (length < adaptive_burst_window_remaining) {
// partial fill
adaptive_burst_window_counter += adaptive_burst_count_samples(buf, length);
adaptive_burst_window_remaining -= length;
return;
}
// complete fill of first partial window
unsigned n = adaptive_burst_window_remaining;
unsigned counter = adaptive_burst_window_counter + adaptive_burst_count_samples(buf, n);
adaptive_burst_end_of_window(counter);
buf += n;
length -= n;
// remaining windows
unsigned windows = length / adaptive_samples_per_window;
unsigned samples = windows * adaptive_samples_per_window;
adaptive_burst_scan_windows(buf, windows);
buf += samples;
length -= samples;
// final partial window
adaptive_burst_window_counter = adaptive_burst_count_samples(buf, length);
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
}
// Burst measurement: process 'windows' complete burst windows starting at 'buf';
// 'buf' is aligned to the start of a burst window
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows)
{
while (windows--) {
unsigned counter = adaptive_burst_count_samples(buf, adaptive_samples_per_window);
buf += adaptive_samples_per_window;
adaptive_burst_end_of_window(counter);
}
}
// Burst measurement: process 'n' samples from 'buf', look for loud samples;
// the samples are guaranteed not to cross window boundaries;
// return the number of loud samples seen
static inline unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n)
{
unsigned counter;
starch_count_above_u16(buf, n, 46395 /* -3dBFS */, &counter);
return counter;
}
// Burst measurement: we reached the end of a burst window with 'counter'
// loud samples seen, handle that window.
static void adaptive_burst_end_of_window(unsigned counter)
{
if (counter > adaptive_samples_per_window / 4) {
// This window is loud, extend any existing run of loud windows
++adaptive_burst_runlength;
} else {
// Quiet window. If we saw a run of loud windows >= 80us long, count
// that as a candidate for an over-amplified message that was
// not decoded.
if (adaptive_burst_runlength >= 2 && adaptive_burst_runlength <= 5)
++adaptive_burst_block_loud_undecoded;
adaptive_burst_runlength = 0;
}
}
// Noise measurement: process 'length' samples from 'buf'.
// The samples will not cross a block boundary.
static void adaptive_range_update(uint16_t *buf, unsigned length)
{
if (!Modes.adaptive_range_control)
return;
adaptive_range_radix_counter += length;
while (length--) {
// do a very simple radix sort of sample magnitudes
// so we can later find the Nth percentile value
++adaptive_range_radix[buf[0]];
++buf;
}
}
// Noise measurement: we reached the end of a block, update
// our noise estimate
static void adaptive_range_end_of_block()
{
if (!Modes.adaptive_range_control)
return;
unsigned n = 0, i = 0;
// measure Nth percentile magnitude
unsigned count_n = adaptive_range_radix_counter * Modes.adaptive_range_percentile / 100;
while (i < 65536 && n <= count_n)
n += adaptive_range_radix[i++];
uint16_t percentile_n = i - 1;
// maintain an EMA of the Nth percentile
adaptive_range_smoothed = adaptive_range_smoothed * (1 - Modes.adaptive_range_alpha) + percentile_n * Modes.adaptive_range_alpha;
// .. report to stats in dBFS
if (adaptive_range_smoothed > 0) {
Modes.stats_current.adaptive_noise_dbfs = 20 * log10(adaptive_range_smoothed / 65536.0);
} else {
Modes.stats_current.adaptive_noise_dbfs = 0;
}
// reset radix sort for the next block
memset(adaptive_range_radix, 0, 65536 * sizeof(unsigned));
adaptive_range_radix_counter = 0;
}
// Burst measurement: we reached the end of a block, update our burst rate estimate
static void adaptive_burst_end_of_block()
{
if (!Modes.adaptive_burst_control)
return;
// scale rates based on the actual duty cycle fraction
// (e.g. if we are only inspecting 2/5 of samples, then scale the rate by 5/2)
double scale = (double)adaptive_subblock_dutycycle_D / adaptive_subblock_dutycycle_N;
// maintain an EMA of the number of undecoded loud bursts seen per block
Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_loud_undecoded;
adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha;
adaptive_burst_block_loud_undecoded = 0;
// maintain an EMA of the number of decoded, but loud, messages seen per block
Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decoded;
adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
adaptive_burst_block_loud_decoded = 0;
}
void flush_stats(uint64_t now);
static void adaptive_increase_gain(const char *why)
{
if (adaptive_set_gain(sdrGetGain() + 1, why))
adaptive_gain_changed();
}
static void adaptive_decrease_gain(const char *why)
{
if (adaptive_set_gain(sdrGetGain() - 1, why))
adaptive_gain_changed();
}
// Adaptive gain: we reached a block boundary. Update measurements and act on them.
static void adaptive_end_of_block()
{
adaptive_range_end_of_block();
adaptive_burst_end_of_block();
adaptive_control_update();
Modes.stats_current.adaptive_valid = true;
unsigned current = Modes.stats_current.adaptive_gain = sdrGetGain();
Modes.stats_current.adaptive_range_gain_limit = adaptive_range_gain_limit;
++Modes.stats_current.adaptive_gain_seconds[current < STATS_GAIN_COUNT ? current : STATS_GAIN_COUNT-1];
}
static void adaptive_control_update()
{
// votes for what to do with the gain
// "gain_not_up" overlaps somewhat with "gain_down", but they are not identical;
// burst control may want to prevent gain from increasing, but not necessarily
// decrease gain.
bool gain_up = false;
const char *gain_up_reason = NULL;
bool gain_down = false;
const char *gain_down_reason = NULL;
bool gain_not_up = false;
int current_gain = sdrGetGain();
if (adaptive_burst_change_timer)
--adaptive_burst_change_timer;
if (adaptive_range_change_timer > 0)
--adaptive_range_change_timer;
if (adaptive_range_rescan_timer > 0)
--adaptive_range_rescan_timer;
if (Modes.adaptive_burst_control && !adaptive_burst_change_timer) {
if (adaptive_burst_loud_undecoded_smoothed > Modes.adaptive_burst_loud_rate) {
adaptive_burst_quiet_blocks = 0;
++adaptive_burst_loud_blocks;
} else if (adaptive_burst_loud_decoded_smoothed < Modes.adaptive_burst_quiet_rate) {
adaptive_burst_loud_blocks = 0;
++adaptive_burst_quiet_blocks;
} else {
adaptive_burst_loud_blocks = 0;
adaptive_burst_quiet_blocks = 0;
}
if (adaptive_burst_loud_blocks >= Modes.adaptive_burst_loud_runlength) {
// we need to reduce gain (further)
gain_down = gain_not_up = true;
gain_down_reason = "high rate of loud undecoded messages";
// if we're currently doing a downward scan, reducing gain further may confuse it;
// stop that scan and restart it once we are no longer in a reduced-gain state
if (adaptive_range_state == RANGE_SCAN_DOWN || adaptive_range_state == RANGE_RESCAN_DOWN) {
adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = 0;
}
} else if (adaptive_burst_quiet_blocks < Modes.adaptive_burst_quiet_runlength) {
// we're OK at the current gain, but should not increase it
gain_not_up = true;
} else if (current_gain < adaptive_range_gain_limit) {
// we're OK at the current gain, and can increase gain to the previously discovered
// dynamic range limit
gain_up = true;
gain_up_reason = "low loud message rate and gain below dynamic range limit";
}
}
if (Modes.adaptive_range_control && !adaptive_range_change_timer) {
float available_range = -20 * log10(adaptive_range_smoothed / 65536.0);
// allow the gain limit to increase if this gain setting is acceptable
// (decreasing the limit is done separately depending on the current state as we make slightly different decisions in IDLE
// to provide hysteresis)
if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit) {
adaptive_range_gain_limit = current_gain;
}
switch (adaptive_range_state) {
case RANGE_SCAN_UP:
case RANGE_RESCAN_UP:
if (available_range < Modes.adaptive_range_target) {
// Current gain fails to meet our target. Switch to downward scanning.
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target);
gain_down = gain_not_up = true;
gain_down_reason = "probing dynamic range gain lower bound";
adaptive_range_state = (adaptive_range_state == RANGE_RESCAN_UP ? RANGE_RESCAN_DOWN : RANGE_SCAN_DOWN);
if (adaptive_range_gain_limit >= current_gain) {
adaptive_range_gain_limit = current_gain - 1;
}
break;
}
if (sdrGetGain() >= adaptive_gain_max) {
// We have reached our upper gain limit
fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n");
adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
break;
}
// This gain step is OK and we have more to try, try the next gain step up.
// (But if burst detection has inhibited increasing gain, don't do anything yet, just try again next block)
if (!gain_not_up) {
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target);
gain_up = true;
gain_up_reason = "probing dynamic range gain upper bound";
}
break;
case RANGE_SCAN_DOWN:
case RANGE_RESCAN_DOWN:
if (available_range >= Modes.adaptive_range_target) {
// Current gain meets our target; we are done with the scan.
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target);
adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = (adaptive_range_state == RANGE_SCAN_DOWN ? Modes.adaptive_range_scan_delay : Modes.adaptive_range_rescan_delay);
break;
}
if (adaptive_range_gain_limit >= current_gain) {
adaptive_range_gain_limit = current_gain - 1;
}
if (sdrGetGain() <= adaptive_gain_min) {
fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n");
adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
break;
}
// This gain step is too loud and we have more to try, try the next gain step down
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target);
gain_down = gain_not_up = true;
gain_down_reason = "probing dynamic range gain lower bound";
break;
case RANGE_SCAN_IDLE:
// Look for increased noise that could be compensated for by decreasing gain.
// Do this even if we're waiting to rescan or if burst control is also active
if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) {
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n",
available_range, Modes.adaptive_range_target, adaptive_gain_down_db);
if (adaptive_range_gain_limit >= current_gain) {
adaptive_range_gain_limit = current_gain - 1;
}
adaptive_range_state = RANGE_SCAN_DOWN;
gain_down = gain_not_up = true;
gain_down_reason = "dynamic range fell below target value";
break;
}
// Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting.
// But don't do this while burst control is preventing gain increases.
if (!adaptive_range_rescan_timer && !gain_not_up) {
if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) {
fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n");
gain_up = true;
gain_up_reason = "periodic re-probing of dynamic range gain upper bound";
adaptive_range_state = RANGE_RESCAN_UP;
break;
}
// Nothing to do for a while.
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
}
break;
default:
fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state);
adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
break;
}
}
// now actually perform any gain changes
if (gain_down)
adaptive_decrease_gain(gain_down_reason);
else if (gain_up && !gain_not_up)
adaptive_increase_gain(gain_up_reason);
}

View File

@ -1,30 +0,0 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// adaptive.h: adaptive gain control prototypes
//
// Copyright (c) 2021 FlightAware, LLC
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef ADAPTIVE_H
#define ADAPTIVE_H
#include <inttypes.h>
struct modesMessage;
void adaptive_init();
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
#endif

257
comm_b.c
View File

@ -29,10 +29,8 @@ static int decodeBDS17(struct modesMessage *mm, bool store);
static int decodeBDS20(struct modesMessage *mm, bool store); static int decodeBDS20(struct modesMessage *mm, bool store);
static int decodeBDS30(struct modesMessage *mm, bool store); static int decodeBDS30(struct modesMessage *mm, bool store);
static int decodeBDS40(struct modesMessage *mm, bool store); static int decodeBDS40(struct modesMessage *mm, bool store);
static int decodeBDS44(struct modesMessage *mm, bool store);
static int decodeBDS50(struct modesMessage *mm, bool store); static int decodeBDS50(struct modesMessage *mm, bool store);
static int decodeBDS60(struct modesMessage *mm, bool store); static int decodeBDS60(struct modesMessage *mm, bool store);
static int decodeBDS05(struct modesMessage *mm, bool store);
static CommBDecoderFn comm_b_decoders[] = { static CommBDecoderFn comm_b_decoders[] = {
&decodeEmptyResponse, &decodeEmptyResponse,
@ -42,18 +40,17 @@ static CommBDecoderFn comm_b_decoders[] = {
&decodeBDS17, &decodeBDS17,
&decodeBDS40, &decodeBDS40,
&decodeBDS50, &decodeBDS50,
&decodeBDS60, &decodeBDS60
&decodeBDS44,
&decodeBDS05
}; };
void decodeCommB(struct modesMessage *mm) void decodeCommB(struct modesMessage *mm)
{ {
mm->commb_format = COMMB_UNKNOWN;
// If DR or UM are set, this message is _probably_ noise // If DR or UM are set, this message is _probably_ noise
// as nothing really seems to use the multisite broadcast stuff? // as nothing really seems to use the multisite broadcast stuff?
// Also skip anything that had errors corrected // Also skip anything that had errors corrected
if (mm->DR != 0 || mm->UM != 0 || mm->correctedbits > 0) { if (mm->DR != 0 || mm->UM != 0 || mm->correctedbits > 0) {
mm->commb_format = COMMB_NOT_DECODED;
return; return;
} }
@ -80,39 +77,12 @@ void decodeCommB(struct modesMessage *mm)
// decode it // decode it
bestDecoder(mm, true); bestDecoder(mm, true);
} }
} else {
mm->commb_format = COMMB_UNKNOWN;
} }
} }
static int decodeEmptyResponse(struct modesMessage *mm, bool store) static int decodeEmptyResponse(struct modesMessage *mm, bool store)
{ {
// 00000000000000 is a common response. Ignore it. for (unsigned i = 0; i < 7; ++i) {
//
// Also, it's common to see responses that look like this:
// 40000000000000
// 50000000000000
// 60000000000000
// typically in grouped bursts (one of each message) from
// the same aircraft.
//
// I speculate that these are response to interrogations for
// BDS 4,0 5,0 and 6,0 respectively where the transponder
// doesn't support the register or has no data loaded for it.
// Treat them like empty responses.
switch (mm->MB[0]) {
case 0x00:
case 0x40:
case 0x50:
case 0x60:
break;
default:
return 0;
}
for (unsigned i = 1; i < 7; ++i) {
if (mm->MB[i] != 0) { if (mm->MB[i] != 0) {
return 0; return 0;
} }
@ -178,10 +148,10 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
score -= 2; score -= 2;
} }
if (getbit(msg, 13)) { // 4,4 meterological routine report if (getbit(msg, 13)) { // 4,4 meterological routine report
score -= 1; score -= 2;
} }
if (getbit(msg, 14)) { // 4,4 meterological hazard report if (getbit(msg, 14)) { // 4,4 meterological hazard report
score -= 1; score -= 2;
} }
if (getbit(msg, 20)) { // 5,4 waypoint 1 if (getbit(msg, 20)) { // 5,4 waypoint 1
score -= 2; score -= 2;
@ -203,11 +173,8 @@ static int decodeBDS17(struct modesMessage *mm, bool store)
} else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) { } else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) {
// not ES capable // not ES capable
score += 1; score += 1;
} else if (!getbit(msg, 1) && !getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
// ES with no position data
score += 3;
} else { } else {
// other combinations, unlikely // partial ES support, unlikely
score -= 12; score -= 12;
} }
@ -773,213 +740,3 @@ static int decodeBDS60(struct modesMessage *mm, bool store)
return score; return score;
} }
// BDS4,4 Meterological routine air report
static int decodeBDS44(struct modesMessage *mm, bool store)
{
unsigned char *msg = mm->MB;
unsigned source = getbits(msg, 1, 4);
unsigned wind_valid = getbit(msg, 5);
unsigned windspeed_raw = getbits(msg, 6, 14);
unsigned winddir_raw = getbits(msg, 15, 23);
// ICAO 9871 is inconsistent, it claims:
// bit 24 sign
// bits 25..34 static air temperature, MSB = 64C, LSB=0.25C, range -128C..+128C
//
// .. but this does not actually work, there is one too many bits in the bitfield
// for the claimed values.
//
// Based on observed data, the most plausible actual layout is:
//
// bit 24 status
// bit 25 sign
// bits 26..34 static air temperature, MSB=64C, LSB=0.25C, range -128C..+128C
unsigned sat_valid = getbit(msg, 24);
unsigned sat_sign = getbit(msg, 25);
unsigned sat_raw = getbits(msg, 26, 34);
unsigned asp_valid = getbit(msg, 35);
unsigned asp_raw = getbits(msg, 36, 46);
unsigned turbulence_valid = getbit(msg, 47);
unsigned turbulence_raw = getbits(msg, 48, 49);
unsigned humidity_valid = getbit(msg, 50);
unsigned humidity_raw = getbits(msg, 51, 56);
if (source == MRAR_SOURCE_INVALID || source >= MRAR_SOURCE_RESERVED)
return 0; // invalid or reserved source
if (!wind_valid || !sat_valid)
return 0; // all valid messages seen in the wild have at least temp + wind
if (!asp_valid && asp_raw != 0)
return 0; // ASP not valid, but non-zero values in the ASP field
if (!turbulence_valid && turbulence_raw != 0)
return 0; // turbulence not valid, but non-zero values in the turbulence field
if (!humidity_valid && humidity_raw != 0)
return 0; // humidity not valid, but non-zero values in the humidity field
int score = 0;
float wind_speed = 0;
float wind_dir = 0;
if (wind_valid) {
wind_dir = winddir_raw * (180.0 / 256.0);
wind_speed = windspeed_raw;
if (windspeed_raw == 0) // possible but uncommon
score += 2;
else if (wind_speed <= 250)
score += 19;
else
return 0;
} else {
score += 1;
}
float sat = 0;
if (sat_valid) {
sat = sat_raw * 0.25;
if (sat_sign)
sat -= 128;
if (sat == 0) // possible but uncommon
score += 2;
else if (sat >= -80 && sat <= 60)
score += 11;
else
return 0;
} else {
score += 1;
}
float asp = 0;
if (asp_valid) {
asp = asp_raw;
if (asp >= 25 && asp <= 1100)
score += 12;
else
return 0;
} else {
score += 1;
}
hazard_t turbulence = HAZARD_NIL;
if (turbulence_valid) {
turbulence = (hazard_t) turbulence_raw;
score += 3;
} else {
score += 1;
}
float humidity = 0;
if (humidity_valid) {
humidity = humidity_raw * (100.0 / 64.0);
score += 7;
} else {
score += 1;
}
if (source == MRAR_SOURCE_DMEDME && wind_valid && sat_valid && score > 0) {
// Some GICB messages can be easily mistaken for a MRAR:
//
// GICB bit 1: BDS 0,5 ES airborne position = 0 ]
// GICB bit 2: BDS 0,6 ES surface position = 0 ]
// GICB bit 3: BDS 0,7 ES status = 1 ]
// GICB bit 4: BDS 0,8 ES type & identification = 1 ] -> MRAR source = 3
// GICB bit 5: BDS 0,9 ES airborne velocity = 1 -> MRAR wind valid bit
// GICB bit 24: BDS 6,0 heading and speed report = 1 -> MRAR temp valid bit
// most trailing bits = 0
//
// so only treat this as MRAR as a last resort
score = 1;
}
if (store) {
mm->commb_format = COMMB_MRAR;
mm->mrar_source_valid = 1;
mm->mrar_source = (mrar_source_t) source;
if (wind_valid) {
mm->wind_valid = 1;
mm->wind_speed = wind_speed;
mm->wind_dir = wind_dir;
}
if (sat_valid) {
mm->temperature_valid = 1;
mm->temperature = sat;
}
if (asp_valid) {
mm->pressure_valid = 1;
mm->pressure = asp;
}
if (turbulence_valid) {
mm->turbulence_valid = 1;
mm->turbulence = turbulence;
}
if (humidity_valid) {
mm->humidity_valid = 1;
mm->humidity = humidity;
}
}
return score;
}
// BDS0,5 extended squitter airborne position
// (apparently this gets queried via comm-b sometimes??)
// We don't try to _use_ this as a position, but we can
// at least try to recognize it, to exclude other
// comm-b types (in particular they can be mistaken for MRAR)
static int decodeBDS05(struct modesMessage *mm, bool store)
{
// We recognize these by matching the position altitude against
// the altitude in the surrounding message, so we need a
// DF20 not a DF21
if (mm->msgtype != 20)
return 0;
unsigned char *msg = mm->MB;
unsigned typecode = getbits(msg, 1, 5);
if (typecode < 9 || typecode > 18)
return 0; // only consider typecodes that could be an airborne position with baro altitude
unsigned t_bit = getbit(msg, 21);
if (t_bit) // unlikely
return 0;
unsigned ac12 = getbits(msg, 9, 20);
if (!ac12)
return 0;
// Insert M=0 to make an AC13 value, match against the
// AC13 value in the surrounding message
unsigned ac13 = ((ac12 & 0x0FC0) << 1) | (ac12 & 0x003F);
if (mm->AC != ac13)
return 0; // no altitude match
unsigned lat = getbits(msg, 23, 39);
unsigned lon = getbits(msg, 40, 56);
if (lat == 0 || lon == 0) // unlikely position
return 0;
if (store) {
mm->commb_format = COMMB_AIRBORNE_POSITION;
// No further decoding done, we don't really trust this
// enough to use as real input to CPR
}
// Score this high enough to override everything else
return 100;
}

View File

@ -58,8 +58,8 @@
* *
*/ */
#include "../compat.h"
#include <mach/mach_time.h> #include "clock_gettime.h"
#include <mach/clock.h> // for clock_get_time #include <mach/clock.h> // for clock_get_time
#include <mach/clock_types.h> // for mach_timespec_t, CALENDAR_CLOCK, etc #include <mach/clock_types.h> // for mach_timespec_t, CALENDAR_CLOCK, etc
#include <mach/kern_return.h> // for KERN_SUCCESS, kern_return_t #include <mach/kern_return.h> // for KERN_SUCCESS, kern_return_t
@ -70,8 +70,6 @@
#include <errno.h> // for EINVAL, errno #include <errno.h> // for EINVAL, errno
#include <unistd.h> // for getpid #include <unistd.h> // for getpid
static mach_timebase_info_data_t __clock_gettime_inf;
int clock_gettime(clockid_t clk_id, struct timespec *tp) int clock_gettime(clockid_t clk_id, struct timespec *tp)
{ {
kern_return_t ret; kern_return_t ret;

View File

@ -1,6 +1,27 @@
#ifndef CLOCK_GETTIME_H #ifndef CLOCK_GETTIME_H
#define CLOCK_GETTIME_H #define CLOCK_GETTIME_H
#include <mach/mach_time.h> // Apple-only, but this isn't inclued on other BSDs
#ifdef _CLOCKID_T_DEFINED_
#define CLOCKID_T
#endif
#ifndef CLOCKID_T
#define CLOCKID_T
typedef enum
{
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID
} clockid_t;
#endif // ifndef CLOCKID_T
struct timespec;
static mach_timebase_info_data_t __clock_gettime_inf;
int clock_gettime(clockid_t clk_id, struct timespec *tp); int clock_gettime(clockid_t clk_id, struct timespec *tp);
#endif // CLOCK_GETTIME_H #endif // CLOCK_GETTIME_H

View File

@ -22,7 +22,10 @@
#include <errno.h> // for errno, EINVAL #include <errno.h> // for errno, EINVAL
#include <time.h> // for nanosleep, NULL #include <time.h> // for nanosleep, NULL
#include "../compat.h" #include "clock_nanosleep.h"
#ifdef MISSING_GETTIME
#include "../clock_gettime/clock_gettime.h" // for clock_gettime
#endif
int clock_nanosleep(clockid_t id, int flags, const struct timespec *ts, int clock_nanosleep(clockid_t id, int flags, const struct timespec *ts,
struct timespec *ots) { struct timespec *ots) {

View File

@ -1,6 +1,28 @@
#ifndef CLOCK_NANOSLEEP_H #ifndef CLOCK_NANOSLEEP_H
#define CLOCK_NANOSLEEP_H #define CLOCK_NANOSLEEP_H
#ifdef _CLOCKID_T_DEFINED_
#define CLOCKID_T
#endif
#ifndef CLOCKID_T
#define CLOCKID_T
typedef enum
{
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID
} clockid_t;
#endif // ifndef CLOCKID_T
#ifndef TIMER_ABSTIME
#define TIMER_ABSTIME 1
#endif // TIMER_ABSTIME
struct timespec;
int clock_nanosleep (clockid_t id, int flags, const struct timespec *ts, int clock_nanosleep (clockid_t id, int flags, const struct timespec *ts,
struct timespec *ots); struct timespec *ots);

View File

@ -17,10 +17,6 @@
# include <machine/endian.h> # include <machine/endian.h>
# define le16toh(x) OSSwapLittleToHostInt16(x) # define le16toh(x) OSSwapLittleToHostInt16(x)
# define le32toh(x) OSSwapLittleToHostInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#else // other platforms #else // other platforms
@ -28,30 +24,6 @@
#endif #endif
/* clock_* and time-related types */
#include <time.h>
#if defined(CLOCK_REALTIME)
# define HAVE_CLOCKID_T
#endif
#ifndef HAVE_CLOCKID_T
typedef enum
{
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID
} clockid_t;
#endif // !HAVE_CLOCKID_T
#ifndef TIMER_ABSTIME
#define TIMER_ABSTIME 1
#endif // !TIMER_ABSTIME
struct timespec;
#ifdef MISSING_NANOSLEEP #ifdef MISSING_NANOSLEEP
#include "clock_nanosleep/clock_nanosleep.h" #include "clock_nanosleep/clock_nanosleep.h"
#endif #endif

480
convert.c
View File

@ -19,7 +19,200 @@
#include "dump1090.h" #include "dump1090.h"
static void convert_uc8(void *iq_data, struct converter_state {
float dc_a;
float dc_b;
float z1_I;
float z1_Q;
};
static uint16_t *uc8_lookup;
static bool init_uc8_lookup()
{
if (uc8_lookup)
return true;
uc8_lookup = malloc(sizeof(uint16_t) * 256 * 256);
if (!uc8_lookup) {
fprintf(stderr, "can't allocate UC8 conversion lookup table\n");
return false;
}
for (int i = 0; i <= 255; i++) {
for (int q = 0; q <= 255; q++) {
float fI, fQ, magsq;
fI = (i - 127.5) / 127.5;
fQ = (q - 127.5) / 127.5;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
uc8_lookup[le16toh((i*256)+q)] = (uint16_t) (mag * 65535.0f + 0.5f);
}
}
return true;
}
static void convert_uc8_nodc(void *iq_data,
uint16_t *mag_data,
unsigned nsamples,
struct converter_state *state,
double *out_mean_level,
double *out_mean_power)
{
uint16_t *in = iq_data;
unsigned i;
uint64_t sum_level = 0;
uint64_t sum_power = 0;
uint16_t mag;
MODES_NOTUSED(state);
// unroll this a bit
#define DO_ONE_SAMPLE \
do { \
mag = uc8_lookup[*in++]; \
*mag_data++ = mag; \
sum_level += mag; \
sum_power += (uint32_t)mag * (uint32_t)mag; \
} while(0)
// unroll this a bit
for (i = 0; i < (nsamples>>3); ++i) {
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
DO_ONE_SAMPLE;
}
for (i = 0; i < (nsamples&7); ++i) {
DO_ONE_SAMPLE;
}
#undef DO_ONE_SAMPLE
if (out_mean_level) {
*out_mean_level = sum_level / 65536.0 / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / 65535.0 / 65535.0 / nsamples;
}
}
static void convert_uc8_generic(void *iq_data,
uint16_t *mag_data,
unsigned nsamples,
struct converter_state *state,
double *out_mean_level,
double *out_mean_power)
{
uint8_t *in = iq_data;
float z1_I = state->z1_I;
float z1_Q = state->z1_Q;
const float dc_a = state->dc_a;
const float dc_b = state->dc_b;
unsigned i;
uint8_t I, Q;
float fI, fQ, magsq;
float sum_level = 0, sum_power = 0;
for (i = 0; i < nsamples; ++i) {
I = *in++;
Q = *in++;
fI = (I - 127.5f) / 127.5f;
fQ = (Q - 127.5f) / 127.5f;
// DC block
z1_I = fI * dc_a + z1_I * dc_b;
z1_Q = fQ * dc_a + z1_Q * dc_b;
fI -= z1_I;
fQ -= z1_Q;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
sum_power += magsq;
sum_level += mag;
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
}
state->z1_I = z1_I;
state->z1_Q = z1_Q;
if (out_mean_level) {
*out_mean_level = sum_level / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / nsamples;
}
}
static void convert_sc16_generic(void *iq_data,
uint16_t *mag_data,
unsigned nsamples,
struct converter_state *state,
double *out_mean_level,
double *out_mean_power)
{
uint16_t *in = iq_data;
float z1_I = state->z1_I;
float z1_Q = state->z1_Q;
const float dc_a = state->dc_a;
const float dc_b = state->dc_b;
unsigned i;
int16_t I, Q;
float fI, fQ, magsq;
float sum_level = 0, sum_power = 0;
for (i = 0; i < nsamples; ++i) {
I = (int16_t)le16toh(*in++);
Q = (int16_t)le16toh(*in++);
fI = I / 32768.0f;
fQ = Q / 32768.0f;
// DC block
z1_I = fI * dc_a + z1_I * dc_b;
z1_Q = fQ * dc_a + z1_Q * dc_b;
fI -= z1_I;
fQ -= z1_Q;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
sum_power += magsq;
sum_level += mag;
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
}
state->z1_I = z1_I;
state->z1_Q = z1_Q;
if (out_mean_level) {
*out_mean_level = sum_level / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / nsamples;
}
}
static void convert_sc16_nodc(void *iq_data,
uint16_t *mag_data, uint16_t *mag_data,
unsigned nsamples, unsigned nsamples,
struct converter_state *state, struct converter_state *state,
@ -28,22 +221,117 @@ static void convert_uc8(void *iq_data,
{ {
MODES_NOTUSED(state); MODES_NOTUSED(state);
const uc8_t *in = (const uc8_t *) iq_data; uint16_t *in = iq_data;
if (out_mean_level && out_mean_power) { unsigned i;
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data)) int16_t I, Q;
starch_magnitude_power_uc8_aligned(in, mag_data, nsamples, out_mean_level, out_mean_power); float fI, fQ, magsq;
else float sum_level = 0, sum_power = 0;
starch_magnitude_power_uc8(in, mag_data, nsamples, out_mean_level, out_mean_power);
} else { for (i = 0; i < nsamples; ++i) {
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data)) I = (int16_t)le16toh(*in++);
starch_magnitude_uc8_aligned(in, mag_data, nsamples); Q = (int16_t)le16toh(*in++);
else fI = I / 32768.0f;
starch_magnitude_uc8(in, mag_data, nsamples); fQ = Q / 32768.0f;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
sum_power += magsq;
sum_level += mag;
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
}
if (out_mean_level) {
*out_mean_level = sum_level / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / nsamples;
} }
} }
static void convert_sc16(void *iq_data, // SC16Q11_TABLE_BITS controls the size of the lookup table
// for SC16Q11 data. The size of the table is 2 * (1 << (2*BITS))
// bytes. Reducing the number of bits reduces precision but
// can run substantially faster by staying in cache.
// See convert_benchmark.c for some numbers.
// Leaving SC16QQ_TABLE_BITS undefined will disable the table lookup and always use
// the floating-point path, which may be faster on some systems
#if defined(SC16Q11_TABLE_BITS)
#define USE_BITS SC16Q11_TABLE_BITS
#define LOSE_BITS (11 - SC16Q11_TABLE_BITS)
static uint16_t *sc16q11_lookup;
static bool init_sc16q11_lookup()
{
if (sc16q11_lookup)
return true;
sc16q11_lookup = malloc(sizeof(uint16_t) * (1 << (USE_BITS * 2)));
if (!sc16q11_lookup) {
fprintf(stderr, "can't allocate SC16Q11 conversion lookup table\n");
return false;
}
for (int i = 0; i < 2048; i += (1 << LOSE_BITS)) {
for (int q = 0; q < 2048; q += (1 << LOSE_BITS)) {
float fI = i / 2048.0, fQ = q / 2048.0;
float magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
unsigned index = ((i >> LOSE_BITS) << USE_BITS) | (q >> LOSE_BITS);
sc16q11_lookup[index] = (uint16_t)(mag * 65535.0f + 0.5f);
}
}
return true;
}
static void convert_sc16q11_table(void *iq_data,
uint16_t *mag_data,
unsigned nsamples,
struct converter_state *state,
double *out_mean_level,
double *out_mean_power)
{
uint16_t *in = iq_data;
unsigned i;
uint16_t I, Q;
uint64_t sum_level = 0;
uint64_t sum_power = 0;
uint16_t mag;
MODES_NOTUSED(state);
for (i = 0; i < nsamples; ++i) {
I = abs((int16_t)le16toh(*in++)) & 2047;
Q = abs((int16_t)le16toh(*in++)) & 2047;
mag = sc16q11_lookup[((I >> LOSE_BITS) << USE_BITS) | (Q >> LOSE_BITS)];
*mag_data++ = mag;
sum_level += mag;
sum_power += (uint32_t)mag * (uint32_t)mag;
}
if (out_mean_level) {
*out_mean_level = sum_level / 65536.0 / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / 65535.0 / 65535.0 / nsamples;
}
}
#else /* ! defined(SC16Q11_TABLE_BITS) */
static void convert_sc16q11_nodc(void *iq_data,
uint16_t *mag_data, uint16_t *mag_data,
unsigned nsamples, unsigned nsamples,
struct converter_state *state, struct converter_state *state,
@ -52,72 +340,162 @@ static void convert_sc16(void *iq_data,
{ {
MODES_NOTUSED(state); MODES_NOTUSED(state);
const sc16_t *in = (const sc16_t *) iq_data; uint16_t *in = iq_data;
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data)) unsigned i;
starch_magnitude_sc16_aligned(in, mag_data, nsamples); int16_t I, Q;
else float fI, fQ, magsq;
starch_magnitude_sc16(in, mag_data, nsamples); float sum_level = 0, sum_power = 0;
if (out_mean_level && out_mean_power) { for (i = 0; i < nsamples; ++i) {
if (STARCH_IS_ALIGNED(mag_data)) I = (int16_t)le16toh(*in++);
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power); Q = (int16_t)le16toh(*in++);
else fI = I / 2048.0f;
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power); fQ = Q / 2048.0f;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
sum_power += magsq;
sum_level += mag;
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
}
if (out_mean_level) {
*out_mean_level = sum_level / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / nsamples;
} }
} }
static void convert_sc16q11(void *iq_data, #endif /* defined(SC16Q11_TABLE_BITS) */
static void convert_sc16q11_generic(void *iq_data,
uint16_t *mag_data, uint16_t *mag_data,
unsigned nsamples, unsigned nsamples,
struct converter_state *state, struct converter_state *state,
double *out_mean_level, double *out_mean_level,
double *out_mean_power) double *out_mean_power)
{ {
MODES_NOTUSED(state); uint16_t *in = iq_data;
float z1_I = state->z1_I;
float z1_Q = state->z1_Q;
const float dc_a = state->dc_a;
const float dc_b = state->dc_b;
const sc16_t *in = (const sc16_t *) iq_data; unsigned i;
int16_t I, Q;
float fI, fQ, magsq;
float sum_level = 0, sum_power = 0;
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data)) for (i = 0; i < nsamples; ++i) {
starch_magnitude_sc16q11_aligned(in, mag_data, nsamples); I = (int16_t)le16toh(*in++);
else Q = (int16_t)le16toh(*in++);
starch_magnitude_sc16q11(in, mag_data, nsamples); fI = I / 2048.0f;
fQ = Q / 2048.0f;
if (out_mean_level && out_mean_power) { // DC block
if (STARCH_IS_ALIGNED(mag_data)) z1_I = fI * dc_a + z1_I * dc_b;
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power); z1_Q = fQ * dc_a + z1_Q * dc_b;
else fI -= z1_I;
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power); fQ -= z1_Q;
magsq = fI * fI + fQ * fQ;
if (magsq > 1)
magsq = 1;
float mag = sqrtf(magsq);
sum_power += magsq;
sum_level += mag;
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
}
state->z1_I = z1_I;
state->z1_Q = z1_Q;
if (out_mean_level) {
*out_mean_level = sum_level / nsamples;
}
if (out_mean_power) {
*out_mean_power = sum_power / nsamples;
} }
} }
static struct {
input_format_t format;
int can_filter_dc;
iq_convert_fn fn;
const char *description;
bool (*init)();
} converters_table[] = {
// In order of preference
{ INPUT_UC8, 0, convert_uc8_nodc, "UC8, integer/table path", init_uc8_lookup },
{ INPUT_UC8, 1, convert_uc8_generic, "UC8, float path", NULL },
{ INPUT_SC16, 0, convert_sc16_nodc, "SC16, float path, no DC", NULL },
{ INPUT_SC16, 1, convert_sc16_generic, "SC16, float path", NULL },
#if defined(SC16Q11_TABLE_BITS)
{ INPUT_SC16Q11, 0, convert_sc16q11_table, "SC16Q11, integer/table path", init_sc16q11_lookup },
#else
{ INPUT_SC16Q11, 0, convert_sc16q11_nodc, "SC16Q11, float path, no DC", NULL },
#endif
{ INPUT_SC16Q11, 1, convert_sc16q11_generic, "SC16Q11, float path", NULL },
{ 0, 0, NULL, NULL, NULL }
};
iq_convert_fn init_converter(input_format_t format, iq_convert_fn init_converter(input_format_t format,
double sample_rate, double sample_rate,
int filter_dc, int filter_dc,
struct converter_state **out_state) struct converter_state **out_state)
{ {
MODES_NOTUSED(sample_rate); int i;
MODES_NOTUSED(out_state);
for (i = 0; converters_table[i].fn; ++i) {
if (converters_table[i].format != format)
continue;
if (filter_dc && !converters_table[i].can_filter_dc)
continue;
break;
}
if (!converters_table[i].fn) {
fprintf(stderr, "no suitable converter for format=%d dc=%d\n",
format, filter_dc);
return NULL;
}
if (converters_table[i].init) {
if (!converters_table[i].init())
return NULL;
}
*out_state = malloc(sizeof(struct converter_state));
if (! *out_state) {
fprintf(stderr, "can't allocate converter state\n");
return NULL;
}
(*out_state)->z1_I = 0;
(*out_state)->z1_Q = 0;
if (filter_dc) { if (filter_dc) {
fprintf(stderr, "DC filtering not supported (yet)\n"); // init DC block @ 1Hz
return NULL; (*out_state)->dc_b = exp(-2.0 * M_PI * 1.0 / sample_rate);
(*out_state)->dc_a = 1.0 - (*out_state)->dc_b;
} else {
// if the converter does filtering, make sure it has no effect
(*out_state)->dc_b = 1.0;
(*out_state)->dc_a = 0.0;
} }
switch (format) { return converters_table[i].fn;
case INPUT_UC8:
return convert_uc8;
case INPUT_SC16:
return convert_sc16;
case INPUT_SC16Q11:
return convert_sc16q11;
default:
fprintf(stderr, "no suitable converter for format=%d\n", format);
return NULL;
}
} }
void cleanup_converter(struct converter_state *state) void cleanup_converter(struct converter_state *state)
{ {
MODES_NOTUSED(state); free(state);
} }

2
cpr.c
View File

@ -47,8 +47,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "cpr.h"
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>

109
cpu.c
View File

@ -1,109 +0,0 @@
#include "cpu.h"
#include <stdbool.h>
#ifdef ENABLE_CPUFEATURES
#include "cpu_features_macros.h"
#endif
//
// x86
//
#ifdef CPU_FEATURES_ARCH_X86
#include "cpuinfo_x86.h"
static X86Info *x86_info()
{
static bool valid = false;
static X86Info cache;
if (!valid) {
cache = GetX86Info();
valid = true;
}
return &cache;
}
#endif
int cpu_supports_avx(void)
{
#ifdef CPU_FEATURES_ARCH_X86
return x86_info()->features.avx;
#else
return 0;
#endif
}
int cpu_supports_avx2(void)
{
#ifdef CPU_FEATURES_ARCH_X86
return x86_info()->features.avx2;
#else
return 0;
#endif
}
//
// ARM
//
#ifdef CPU_FEATURES_ARCH_ARM
#include "cpuinfo_arm.h"
static ArmInfo *arm_info()
{
static bool valid = false;
static ArmInfo cache;
if (!valid) {
cache = GetArmInfo();
valid = true;
}
return &cache;
}
#endif
int cpu_supports_armv7_neon_vfpv4(void)
{
#ifdef CPU_FEATURES_ARCH_ARM
return arm_info()->architecture >= 7 && arm_info()->features.neon && arm_info()->features.vfpv4 && arm_info()->features.vfpd32;
#else
return 0;
#endif
}
//
// AARCH64
//
#ifdef CPU_FEATURES_ARCH_AARCH64
#include "cpuinfo_aarch64.h"
static Aarch64Info *aarch64_info()
{
static bool valid = false;
static Aarch64Info cache;
if (!valid) {
cache = GetAarch64Info();
valid = true;
}
return &cache;
}
#endif
int cpu_supports_armv8_simd(void)
{
#ifdef CPU_FEATURES_ARCH_AARCH64
return aarch64_info()->features.asimd;
#else
return 0;
#endif
}

15
cpu.h
View File

@ -1,15 +0,0 @@
#ifndef DUMP1090_CPU_H
#define DUMP1090_CPU_H
// x86
int cpu_supports_avx(void);
int cpu_supports_avx2(void);
// ARM
int cpu_supports_armv7_neon_vfpv4(void);
// AARCH64
int cpu_supports_armv8_simd(void);
int cpu_supports_armv8_simd_sve(void);
#endif

View File

@ -1,4 +0,0 @@
---
Language: Cpp
BasedOnStyle: Google
...

View File

@ -1,4 +0,0 @@
cmake_build/
build/
*.swp

View File

@ -1,121 +0,0 @@
language: c
sudo: false
cache:
timeout: 1000
directories:
- $HOME/cpu_features_archives
addons:
apt_packages:
- ninja-build
env:
global:
TOOLCHAIN=NATIVE
CMAKE_GENERATOR=Ninja
matrix:
include:
- os: linux
compiler: gcc
env:
TARGET=x86_64-linux-gnu
- os: linux
compiler: clang
env:
TARGET=x86_64-linux-gnu
- os: osx
compiler: gcc
env:
TARGET=x86_64-osx
CMAKE_GENERATOR="Unix Makefiles"
- os: osx
compiler: clang
env:
TARGET=x86_64-osx
CMAKE_GENERATOR="Unix Makefiles"
- os: windows
env:
TARGET=x86_64-windows
CMAKE_GENERATOR="Visual Studio 15 2017 Win64"
# see: https://docs.travis-ci.com/user/multi-cpu-architectures/
- os: linux
arch: ppc64le
compiler: gcc
env:
TARGET=ppc64le-linux-gnu
- os: linux
arch: ppc64le
compiler: clang
env:
TARGET=ppc64le-linux-gnu
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=aarch64-linux-gnu
QEMU_ARCH=aarch64
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=arm-linux-gnueabihf
QEMU_ARCH=arm
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=armv8l-linux-gnueabihf
QEMU_ARCH=arm
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=arm-linux-gnueabi
QEMU_ARCH=arm
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=aarch64_be-linux-gnu
QEMU_ARCH=DISABLED
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=armeb-linux-gnueabihf
QEMU_ARCH=DISABLED
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
- os: linux
env:
TOOLCHAIN=LINARO
TARGET=armeb-linux-gnueabi
QEMU_ARCH=DISABLED
- os: linux
env:
TOOLCHAIN=CODESCAPE
TARGET=mips32
QEMU_ARCH=mips
- os: linux
env:
TOOLCHAIN=CODESCAPE
TARGET=mips32el
QEMU_ARCH=mipsel
- os: linux
env:
TOOLCHAIN=CODESCAPE
TARGET=mips64
QEMU_ARCH=mips64
- os: linux
env:
TOOLCHAIN=CODESCAPE
TARGET=mips64el
QEMU_ARCH=mips64el
script:
- cmake --version
- bash -e -x ./scripts/run_integration.sh

View File

@ -1,259 +0,0 @@
cmake_minimum_required(VERSION 3.0)
# option() honors normal variables.
# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html
if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
project(CpuFeatures VERSION 0.6.0 LANGUAGES C)
set(CMAKE_C_STANDARD 99)
# Default Build Type to be Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
# BUILD_TESTING is a standard CMake variable, but we declare it here to make it
# prominent in the GUI.
option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
# it prominent in the GUI.
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
# Prefer static linking from source whenever possible.
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
# PIC
option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
# Force PIC on unix when building shared libs
# see: https://en.wikipedia.org/wiki/Position-independent_code
if(BUILD_SHARED_LIBS AND UNIX)
set(BUILD_PIC ON)
endif()
include(CheckIncludeFile)
include(CheckSymbolExists)
include(GNUInstallDirs)
macro(setup_include_and_definitions TARGET_NAME)
target_include_directories(${TARGET_NAME}
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/internal>
)
target_compile_definitions(${TARGET_NAME}
PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024
)
endmacro()
set(PROCESSOR_IS_MIPS FALSE)
set(PROCESSOR_IS_ARM FALSE)
set(PROCESSOR_IS_AARCH64 FALSE)
set(PROCESSOR_IS_X86 FALSE)
set(PROCESSOR_IS_POWER FALSE)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
set(PROCESSOR_IS_MIPS TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
set(PROCESSOR_IS_ARM TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
set(PROCESSOR_IS_AARCH64 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
set(PROCESSOR_IS_X86 TRUE)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
set(PROCESSOR_IS_POWER TRUE)
endif()
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
if(PROCESSOR_IS_MIPS)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_mips.c)
elseif(PROCESSOR_IS_ARM)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_arm.c)
elseif(PROCESSOR_IS_AARCH64)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_aarch64.c)
elseif(PROCESSOR_IS_X86)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_x86.c)
elseif(PROCESSOR_IS_POWER)
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_ppc.c)
else()
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
endif()
endmacro()
#
# library : utils
#
add_library(utils OBJECT
${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h
${PROJECT_SOURCE_DIR}/include/internal/filesystem.h
${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h
${PROJECT_SOURCE_DIR}/include/internal/string_view.h
${PROJECT_SOURCE_DIR}/src/filesystem.c
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
${PROJECT_SOURCE_DIR}/src/string_view.c
)
set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
setup_include_and_definitions(utils)
#
# library : unix_based_hardware_detection
#
if(UNIX)
add_library(unix_based_hardware_detection OBJECT
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
${PROJECT_SOURCE_DIR}/src/hwcaps.c
)
setup_include_and_definitions(unix_based_hardware_detection)
check_include_file(dlfcn.h HAVE_DLFCN_H)
if(HAVE_DLFCN_H)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H)
endif()
check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL)
if(HAVE_STRONG_GETAUXVAL)
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
endif()
set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
endif()
#
# library : cpu_features
#
set (CPU_FEATURES_HDRS)
set (CPU_FEATURES_SRCS)
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
if(NOT PROCESSOR_IS_X86 AND UNIX)
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:unix_based_hardware_detection>)
endif()
add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
setup_include_and_definitions(cpu_features)
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
target_include_directories(cpu_features
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
)
if(PROCESSOR_IS_X86)
if(APPLE)
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
endif()
endif()
add_library(CpuFeature::cpu_features ALIAS cpu_features)
#
# program : list_cpu_features
#
add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c)
target_link_libraries(list_cpu_features PRIVATE cpu_features)
add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features)
#
# ndk_compat
#
if(ANDROID)
add_subdirectory(ndk_compat)
endif()
#
# tests
#
include(CTest)
if(BUILD_TESTING)
# Automatically incorporate googletest into the CMake Project if target not
# found.
enable_language(CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11
if(NOT TARGET gtest OR NOT TARGET gmock_main)
# Download and unpack googletest at configure time.
configure_file(
cmake/googletest.CMakeLists.txt.in
googletest-download/CMakeLists.txt
)
execute_process(
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker settings on
# Windows.
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest and
# gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
endif()
add_subdirectory(test)
endif()
#
# Install cpu_features and list_cpu_features
#
include(GNUInstallDirs)
install(TARGETS cpu_features list_cpu_features
EXPORT CpuFeaturesTargets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(EXPORT CpuFeaturesTargets
NAMESPACE CpuFeatures::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures
COMPONENT Devel
)
include(CMakePackageConfigHelpers)
configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
)
install(
FILES
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
COMPONENT Devel
)

View File

@ -1,23 +0,0 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

View File

@ -1,230 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
For files in the `ndk_compat` folder:
--------------------------------------------------------------------------------
Copyright (C) 2010 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@ -1,199 +0,0 @@
# cpu_features [![Build Status](https://travis-ci.org/google/cpu_features.svg?branch=master)](https://travis-ci.org/google/cpu_features) [![Build status](https://ci.appveyor.com/api/projects/status/46d1owsj7n8dsylq/branch/master?svg=true)](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master)
A cross-platform C library to retrieve CPU features (such as available
instructions) at runtime.
## Table of Contents
- [Design Rationale](#rationale)
- [Code samples](#codesample)
- [Running sample code](#usagesample)
- [What's supported](#support)
- [Android NDK's drop in replacement](#ndk)
- [License](#license)
- [Build with cmake](#cmake)
<a name="rationale"></a>
## Design Rationale
- **Simple to use.** See the snippets below for examples.
- **Extensible.** Easy to add missing features or architectures.
- **Compatible with old compilers** and available on many architectures so it
can be used widely. To ensure that cpu_features works on as many platforms
as possible, we implemented it in a highly portable version of C: C99.
- **Sandbox-compatible.** The library uses a variety of strategies to cope
with sandboxed environments or when `cpuid` is unavailable. This is useful
when running integration tests in hermetic environments.
- **Thread safe, no memory allocation, and raises no exceptions.**
cpu_features is suitable for implementing fundamental libc functions like
`malloc`, `memcpy`, and `memcmp`.
- **Unit tested.**
<a name="codesample"></a>
## Code samples
**Note:** For C++ code, the library functions are defined in the `CpuFeatures` namespace.
### Checking features at runtime
Here's a simple example that executes a codepath if the CPU supports both the
AES and the SSE4.2 instruction sets:
```c
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Features features = GetX86Info().features;
void Compute(void) {
if (features.aes && features.sse4_2) {
// Run optimized code.
} else {
// Run standard code.
}
}
```
### Caching for faster evaluation of complex checks
If you wish, you can read all the features at once into a global variable, and
then query for the specific features you care about. Below, we store all the ARM
features and then check whether AES and NEON are supported.
```c
#include <stdbool.h>
#include "cpuinfo_arm.h"
// For C++, add `using namespace CpuFeatures;`
static const ArmFeatures features = GetArmInfo().features;
static const bool has_aes_and_neon = features.aes && features.neon;
// use has_aes_and_neon.
```
This is a good approach to take if you're checking for combinations of features
when using a compiler that is slow to extract individual bits from bit-packed
structures.
### Checking compile time flags
The following code determines whether the compiler was told to use the AVX
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Features features = GetX86Info().features;
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
// use has_avx.
```
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
use AVX and 0 otherwise, combining compile time and runtime knowledge.
### Rejecting poor hardware implementations based on microarchitecture
On x86, the first incarnation of a feature in a microarchitecture might not be
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
the underlying microarchitecture so you can decide whether to use it.
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
set&mdash;but only if it's not Sandy Bridge.
```c
#include <stdbool.h>
#include "cpuinfo_x86.h"
// For C++, add `using namespace CpuFeatures;`
static const X86Info info = GetX86Info();
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
// use has_fast_avx.
```
This feature is currently available only for x86 microarchitectures.
<a name="usagesample"></a>
### Running sample code
Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library.
```shell
% ./build/list_cpu_features
arch : x86
brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz
family : 6 (0x06)
model : 45 (0x2D)
stepping : 7 (0x07)
uarch : INTEL_SNB
flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
```
```shell
% ./build/list_cpu_features --json
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
```
<a name="support"></a>
## What's supported
| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
|---------|:----:|:-------:|:-------:|:------:|:-------:|
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
| iOS | N/A | not yet | not yet | N/A | N/A |
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
| MacOs | yes² | N/A | not yet | N/A | no |
| Windows | yes² | not yet | not yet | N/A | N/A |
1. **Features revealed from Linux.** We gather data from several sources
depending on availability:
+ from glibc's
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
+ by parsing `/proc/self/auxv`
+ by parsing `/proc/cpuinfo`
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
instruction.
3. **Microarchitecture detection.** On x86 some features are not always
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
microarchitecture allows the client to reject particular microarchitectures.
4. All flavors of Mips are supported, little and big endian as well as 32/64
bits.
<a name="ndk"></a>
## Android NDK's drop in replacement
[cpu_features](https://github.com/google/cpu_features) is now officially
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h)
, see [ndk_compat](ndk_compat) folder for details.
<a name="license"></a>
## License
The cpu_features library is licensed under the terms of the Apache license.
See [LICENSE](LICENSE) for more information.
<a name="cmake"></a>
## Build with CMake
Please check the [CMake build instructions](cmake/README.md).
<a name="quickstart"></a>
### Quickstart with `Ninja`
- build `list_cpu_features`
```
cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release
ninja -C/tmp/cpu_features
/tmp/cpu_features/list_cpu_features --json
```
- run tests
```
cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON
ninja -C/tmp/cpu_features
ninja -C/tmp/cpu_features test
```

View File

@ -1,7 +0,0 @@
# ===== googletest =====
git_repository(
name = "com_google_googletest",
remote = "https://github.com/google/googletest.git",
commit = "c3f65335b79f47b05629e79a54685d899bc53b93",
)

View File

@ -1,24 +0,0 @@
version: '{build}'
shallow_clone: true
platform: x64
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_GENERATOR: "Visual Studio 14 2015 Win64"
matrix:
fast_finish: true
before_build:
- cmake --version
- cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -H. -Bcmake_build -G "%CMAKE_GENERATOR%"
build_script:
- cmake --build cmake_build --config Debug --target ALL_BUILD
test_script:
- cmake --build cmake_build --config Debug --target RUN_TESTS

View File

@ -1,3 +0,0 @@
# CpuFeatures CMake configuration file
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake")

View File

@ -1,3 +0,0 @@
# CpuFeaturesNdkCompat CMake configuration file
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake")

View File

@ -1,28 +0,0 @@
# CMake build instructions
## Recommended usage : Incorporating cpu_features into a CMake project
For API / ABI compatibility reasons, it is recommended to build and use
cpu_features in a subdirectory of your project or as an embedded dependency.
This is similar to the recommended usage of the googletest framework
( https://github.com/google/googletest/blob/master/googletest/README.md )
Build and use step-by-step
1- Download cpu_features and copy it in a sub-directory in your project.
or add cpu_features as a git-submodule in your project
2- You can then use the cmake command `add_subdirectory()` to include
cpu_features directly and use the `cpu_features` target in your project.
3- Add the `cpu_features` target to the `target_link_libraries()` section of
your executable or of your library.
## Enabling tests
CMake default options for cpu_features is Release built type with tests
disabled. To enable testing set cmake `BUILD_TESTING` variable to `ON`,
[.travis.yml](../.travis.yml) and [appveyor.yml](../appveyor.yml) have up to
date examples.

View File

@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@ -1,54 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef enum {
CPU_FEATURE_CACHE_NULL = 0,
CPU_FEATURE_CACHE_DATA = 1,
CPU_FEATURE_CACHE_INSTRUCTION = 2,
CPU_FEATURE_CACHE_UNIFIED = 3,
CPU_FEATURE_CACHE_TLB = 4,
CPU_FEATURE_CACHE_DTLB = 5,
CPU_FEATURE_CACHE_STLB = 6,
CPU_FEATURE_CACHE_PREFETCH = 7
} CacheType;
typedef struct {
int level;
CacheType cache_type;
int cache_size; // Cache size in bytes
int ways; // Associativity, 0 undefined, 0xFF fully associative
int line_size; // Cache line size in bytes
int tlb_entries; // number of entries for TLB
int partitioning; // number of lines per sector
} CacheLevelInfo;
// Increase this value if more cache levels are needed.
#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
#define CPU_FEATURES_MAX_CACHE_LEVEL 10
#endif
typedef struct {
int size;
CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
} CacheInfo;
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_

View File

@ -1,216 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
////////////////////////////////////////////////////////////////////////////////
// Architectures
////////////////////////////////////////////////////////////////////////////////
#if defined(__pnacl__) || defined(__CLR_VER)
#define CPU_FEATURES_ARCH_VM
#endif
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_32
#endif
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
#define CPU_FEATURES_ARCH_X86_64
#endif
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
#define CPU_FEATURES_ARCH_X86
#endif
#if (defined(__arm__) || defined(_M_ARM))
#define CPU_FEATURES_ARCH_ARM
#endif
#if defined(__aarch64__)
#define CPU_FEATURES_ARCH_AARCH64
#endif
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
#define CPU_FEATURES_ARCH_ANY_ARM
#endif
#if defined(__mips64)
#define CPU_FEATURES_ARCH_MIPS64
#endif
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
#define CPU_FEATURES_ARCH_MIPS32
#endif
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
#define CPU_FEATURES_ARCH_MIPS
#endif
#if defined(__powerpc__)
#define CPU_FEATURES_ARCH_PPC
#endif
////////////////////////////////////////////////////////////////////////////////
// Os
////////////////////////////////////////////////////////////////////////////////
#if defined(__linux__)
#define CPU_FEATURES_OS_LINUX_OR_ANDROID
#endif
#if defined(__ANDROID__)
#define CPU_FEATURES_OS_ANDROID
#endif
#if (defined(_WIN64) || defined(_WIN32))
#define CPU_FEATURES_OS_WINDOWS
#endif
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
#define CPU_FEATURES_OS_DARWIN
#endif
////////////////////////////////////////////////////////////////////////////////
// Compilers
////////////////////////////////////////////////////////////////////////////////
#if defined(__clang__)
#define CPU_FEATURES_COMPILER_CLANG
#endif
#if defined(__GNUC__) && !defined(__clang__)
#define CPU_FEATURES_COMPILER_GCC
#endif
#if defined(_MSC_VER)
#define CPU_FEATURES_COMPILER_MSC
#endif
////////////////////////////////////////////////////////////////////////////////
// Cpp
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
#define CPU_FEATURES_START_CPP_NAMESPACE \
namespace cpu_features { \
extern "C" {
#define CPU_FEATURES_END_CPP_NAMESPACE \
} \
}
#else
#define CPU_FEATURES_START_CPP_NAMESPACE
#define CPU_FEATURES_END_CPP_NAMESPACE
#endif
////////////////////////////////////////////////////////////////////////////////
// Compiler flags
////////////////////////////////////////////////////////////////////////////////
// Use the following to check if a feature is known to be available at
// compile time. See README.md for an example.
#if defined(CPU_FEATURES_ARCH_X86)
#if defined(__AES__)
#define CPU_FEATURES_COMPILED_X86_AES 1
#else
#define CPU_FEATURES_COMPILED_X86_AES 0
#endif // defined(__AES__)
#if defined(__F16C__)
#define CPU_FEATURES_COMPILED_X86_F16C 1
#else
#define CPU_FEATURES_COMPILED_X86_F16C 0
#endif // defined(__F16C__)
#if defined(__BMI__)
#define CPU_FEATURES_COMPILED_X86_BMI 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI 0
#endif // defined(__BMI__)
#if defined(__BMI2__)
#define CPU_FEATURES_COMPILED_X86_BMI2 1
#else
#define CPU_FEATURES_COMPILED_X86_BMI2 0
#endif // defined(__BMI2__)
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
#define CPU_FEATURES_COMPILED_X86_SSE 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE 0
#endif
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
#define CPU_FEATURES_COMPILED_X86_SSE2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE2 0
#endif
#if defined(__SSE3__)
#define CPU_FEATURES_COMPILED_X86_SSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE3 0
#endif // defined(__SSE3__)
#if defined(__SSSE3__)
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
#else
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
#endif // defined(__SSSE3__)
#if defined(__SSE4_1__)
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
#endif // defined(__SSE4_1__)
#if defined(__SSE4_2__)
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
#else
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
#endif // defined(__SSE4_2__)
#if defined(__AVX__)
#define CPU_FEATURES_COMPILED_X86_AVX 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX 0
#endif // defined(__AVX__)
#if defined(__AVX2__)
#define CPU_FEATURES_COMPILED_X86_AVX2 1
#else
#define CPU_FEATURES_COMPILED_X86_AVX2 0
#endif // defined(__AVX2__)
#endif // defined(CPU_FEATURES_ARCH_X86)
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(__ARM_NEON__)
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
#else
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
#endif // defined(__ARM_NEON__)
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
#if defined(CPU_FEATURES_ARCH_MIPS)
#if defined(__mips_msa)
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
#else
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
#endif // defined(__mips_msa)
#endif // defined(CPU_FEATURES_ARCH_MIPS)
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_

View File

@ -1,156 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int fp : 1; // Floating-point.
int asimd : 1; // Advanced SIMD.
int evtstrm : 1; // Generic timer generated events.
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
int atomics : 1; // Armv8.1 atomic instructions.
int fphp : 1; // Half-precision floating point support.
int asimdhp : 1; // Advanced SIMD half-precision support.
int cpuid : 1; // Access to certain ID registers.
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
int jscvt : 1; // Support for JavaScript conversion.
int fcma : 1; // Floating point complex numbers.
int lrcpc : 1; // Support for weaker release consistency.
int dcpop : 1; // Data persistence writeback.
int sha3 : 1; // Hardware-accelerated SHA3.
int sm3 : 1; // Hardware-accelerated SM3.
int sm4 : 1; // Hardware-accelerated SM4.
int asimddp : 1; // Dot product instruction.
int sha512 : 1; // Hardware-accelerated SHA512.
int sve : 1; // Scalable Vector Extension.
int asimdfhm : 1; // Additional half-precision instructions.
int dit : 1; // Data independent timing.
int uscat : 1; // Unaligned atomics support.
int ilrcpc : 1; // Additional support for weaker release consistency.
int flagm : 1; // Flag manipulation instructions.
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
int sb : 1; // Speculation barrier.
int paca : 1; // Address authentication.
int pacg : 1; // Generic authentication.
int dcpodp : 1; // Data cache clean to point of persistence.
int sve2 : 1; // Scalable Vector Extension (version 2).
int sveaes : 1; // SVE AES instructions.
int svepmull : 1; // SVE polynomial multiply long instructions.
int svebitperm : 1; // SVE bit permute instructions.
int svesha3 : 1; // SVE SHA3 instructions.
int svesm4 : 1; // SVE SM4 instructions.
int flagm2 : 1; // Additional flag manipulation instructions.
int frint : 1; // Floating point to integer rounding.
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
int svebf16 : 1; // SVE BFloat16 instructions.
int i8mm : 1; // Int8 matrix multiplication instructions.
int bf16 : 1; // BFloat16 instructions.
int dgh : 1; // Data Gathering Hint instruction.
int rng : 1; // True random number generator support.
int bti : 1; // Branch target identification.
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
} Aarch64Features;
typedef struct {
Aarch64Features features;
int implementer;
int variant;
int part;
int revision;
} Aarch64Info;
Aarch64Info GetAarch64Info(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
AARCH64_FP,
AARCH64_ASIMD,
AARCH64_EVTSTRM,
AARCH64_AES,
AARCH64_PMULL,
AARCH64_SHA1,
AARCH64_SHA2,
AARCH64_CRC32,
AARCH64_ATOMICS,
AARCH64_FPHP,
AARCH64_ASIMDHP,
AARCH64_CPUID,
AARCH64_ASIMDRDM,
AARCH64_JSCVT,
AARCH64_FCMA,
AARCH64_LRCPC,
AARCH64_DCPOP,
AARCH64_SHA3,
AARCH64_SM3,
AARCH64_SM4,
AARCH64_ASIMDDP,
AARCH64_SHA512,
AARCH64_SVE,
AARCH64_ASIMDFHM,
AARCH64_DIT,
AARCH64_USCAT,
AARCH64_ILRCPC,
AARCH64_FLAGM,
AARCH64_SSBS,
AARCH64_SB,
AARCH64_PACA,
AARCH64_PACG,
AARCH64_DCPODP,
AARCH64_SVE2,
AARCH64_SVEAES,
AARCH64_SVEPMULL,
AARCH64_SVEBITPERM,
AARCH64_SVESHA3,
AARCH64_SVESM4,
AARCH64_FLAGM2,
AARCH64_FRINT,
AARCH64_SVEI8MM,
AARCH64_SVEF32MM,
AARCH64_SVEF64MM,
AARCH64_SVEBF16,
AARCH64_I8MM,
AARCH64_BF16,
AARCH64_DGH,
AARCH64_RNG,
AARCH64_BTI,
AARCH64_LAST_,
} Aarch64FeaturesEnum;
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value);
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_AARCH64)
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_

View File

@ -1,121 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
#include <stdint.h> // uint32_t
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int swp : 1; // SWP instruction (atomic read-modify-write)
int half : 1; // Half-word loads and stores
int thumb : 1; // Thumb (16-bit instruction set)
int _26bit : 1; // "26 Bit" Model (Processor status register folded into
// program counter)
int fastmult : 1; // 32x32->64-bit multiplication
int fpa : 1; // Floating point accelerator
int vfp : 1; // Vector Floating Point.
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all
// others above)
int java : 1; // Jazelle (Java bytecode accelerator)
int iwmmxt : 1; // Intel Wireless MMX Technology.
int crunch : 1; // MaverickCrunch coprocessor
int thumbee : 1; // ThumbEE
int neon : 1; // Advanced SIMD.
int vfpv3 : 1; // VFP version 3
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
int tls : 1; // TLS register
int vfpv4 : 1; // VFP version 4 with fast context switching
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
int vfpd32 : 1; // VFP with 32 D-registers
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on
// 32-bit architecture)
int evtstrm : 1; // kernel event stream using generic architected timer
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
int pmull : 1; // Polynomial multiply long.
int sha1 : 1; // Hardware-accelerated SHA1.
int sha2 : 1; // Hardware-accelerated SHA2-256.
int crc32 : 1; // Hardware-accelerated CRC-32.
// Make sure to update ArmFeaturesEnum below if you add a field here.
} ArmFeatures;
typedef struct {
ArmFeatures features;
int implementer;
int architecture;
int variant;
int part;
int revision;
} ArmInfo;
// TODO(user): Add macros to know which features are present at compile
// time.
ArmInfo GetArmInfo(void);
// Compute CpuId from ArmInfo.
uint32_t GetArmCpuId(const ArmInfo* const info);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
ARM_SWP,
ARM_HALF,
ARM_THUMB,
ARM_26BIT,
ARM_FASTMULT,
ARM_FPA,
ARM_VFP,
ARM_EDSP,
ARM_JAVA,
ARM_IWMMXT,
ARM_CRUNCH,
ARM_THUMBEE,
ARM_NEON,
ARM_VFPV3,
ARM_VFPV3D16,
ARM_TLS,
ARM_VFPV4,
ARM_IDIVA,
ARM_IDIVT,
ARM_VFPD32,
ARM_LPAE,
ARM_EVTSTRM,
ARM_AES,
ARM_PMULL,
ARM_SHA1,
ARM_SHA2,
ARM_CRC32,
ARM_LAST_,
} ArmFeaturesEnum;
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_ARM)
#error "Including cpuinfo_arm.h from a non-arm target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_

View File

@ -1,60 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int msa : 1; // MIPS SIMD Architecture
// https://www.mips.com/products/architectures/ase/simd/
int eva : 1; // Enhanced Virtual Addressing
// https://www.mips.com/products/architectures/mips64/
int r6 : 1; // True if is release 6 of the processor.
// Make sure to update MipsFeaturesEnum below if you add a field here.
} MipsFeatures;
typedef struct {
MipsFeatures features;
} MipsInfo;
MipsInfo GetMipsInfo(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
MIPS_MSA,
MIPS_EVA,
MIPS_R6,
MIPS_LAST_,
} MipsFeaturesEnum;
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
MipsFeaturesEnum value);
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_MIPS)
#error "Including cpuinfo_mips.h from a non-mips target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_

View File

@ -1,146 +0,0 @@
// Copyright 2018 IBM
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
#include "internal/hwcaps.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
int ppc32 : 1;
int ppc64 : 1;
int ppc601 : 1;
int altivec : 1;
int fpu : 1;
int mmu : 1;
int mac_4xx : 1;
int unifiedcache : 1;
int spe : 1;
int efpsingle : 1;
int efpdouble : 1;
int no_tb : 1;
int power4 : 1;
int power5 : 1;
int power5plus : 1;
int cell : 1;
int booke : 1;
int smt : 1;
int icachesnoop : 1;
int arch205 : 1;
int pa6t : 1;
int dfp : 1;
int power6ext : 1;
int arch206 : 1;
int vsx : 1;
int pseries_perfmon_compat : 1;
int truele : 1;
int ppcle : 1;
int arch207 : 1;
int htm : 1;
int dscr : 1;
int ebb : 1;
int isel : 1;
int tar : 1;
int vcrypto : 1;
int htm_nosc : 1;
int arch300 : 1;
int ieee128 : 1;
int darn : 1;
int scv : 1;
int htm_no_suspend : 1;
// Make sure to update PPCFeaturesEnum below if you add a field here.
} PPCFeatures;
typedef struct {
PPCFeatures features;
} PPCInfo;
// This function is guaranteed to be malloc, memset and memcpy free.
PPCInfo GetPPCInfo(void);
typedef struct {
char platform[64]; // 0 terminated string
char model[64]; // 0 terminated string
char machine[64]; // 0 terminated string
char cpu[64]; // 0 terminated string
PlatformType type;
} PPCPlatformStrings;
PPCPlatformStrings GetPPCPlatformStrings(void);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
PPC_32, /* 32 bit mode execution */
PPC_64, /* 64 bit mode execution */
PPC_601_INSTR, /* Old POWER ISA */
PPC_HAS_ALTIVEC, /* SIMD Unit*/
PPC_HAS_FPU, /* Floating Point Unit */
PPC_HAS_MMU, /* Memory management unit */
PPC_HAS_4xxMAC,
PPC_UNIFIED_CACHE, /* Unified instruction and data cache */
PPC_HAS_SPE, /* Signal processing extention unit */
PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */
PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */
PPC_NO_TB, /* No timebase */
PPC_POWER4,
PPC_POWER5,
PPC_POWER5_PLUS,
PPC_CELL, /* Cell broadband engine */
PPC_BOOKE, /* Embedded ISA */
PPC_SMT, /* Simultaneous multi-threading */
PPC_ICACHE_SNOOP,
PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */
PPC_PA6T, /* PA Semi 6T core ISA */
PPC_HAS_DFP, /* Decimal floating point unit */
PPC_POWER6_EXT,
PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */
PPC_HAS_VSX, /* Vector-scalar extension */
PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance
monitoring events */
PPC_TRUE_LE,
PPC_PPC_LE,
PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */
PPC_HTM, /* Hardware Transactional Memory */
PPC_DSCR, /* Data stream control register */
PPC_EBB, /* Event base branching */
PPC_ISEL, /* Integer select instructions */
PPC_TAR, /* Target address register */
PPC_VEC_CRYPTO, /* Vector cryptography instructions */
PPC_HTM_NOSC, /* Transactions aborted when syscall made*/
PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */
PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */
PPC_DARN, /* Deliver a random number instruction */
PPC_SCV, /* scv syscall */
PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */
PPC_LAST_,
} PPCFeaturesEnum;
int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value);
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_PPC)
#error "Including cpuinfo_ppc.h from a non-ppc target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_

View File

@ -1,231 +0,0 @@
// Copyright 2017 Google LLC
// Copyright 2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
#include "cpu_features_cache_info.h"
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
// The field names are based on the short name provided in the wikipedia tables.
typedef struct {
int fpu : 1;
int tsc : 1;
int cx8 : 1;
int clfsh : 1;
int mmx : 1;
int aes : 1;
int erms : 1;
int f16c : 1;
int fma4 : 1;
int fma3 : 1;
int vaes : 1;
int vpclmulqdq : 1;
int bmi1 : 1;
int hle : 1;
int bmi2 : 1;
int rtm : 1;
int rdseed : 1;
int clflushopt : 1;
int clwb : 1;
int sse : 1;
int sse2 : 1;
int sse3 : 1;
int ssse3 : 1;
int sse4_1 : 1;
int sse4_2 : 1;
int sse4a : 1;
int avx : 1;
int avx2 : 1;
int avx512f : 1;
int avx512cd : 1;
int avx512er : 1;
int avx512pf : 1;
int avx512bw : 1;
int avx512dq : 1;
int avx512vl : 1;
int avx512ifma : 1;
int avx512vbmi : 1;
int avx512vbmi2 : 1;
int avx512vnni : 1;
int avx512bitalg : 1;
int avx512vpopcntdq : 1;
int avx512_4vnniw : 1;
int avx512_4vbmi2 : 1;
int avx512_second_fma : 1;
int avx512_4fmaps : 1;
int avx512_bf16 : 1;
int avx512_vp2intersect : 1;
int amx_bf16 : 1;
int amx_tile : 1;
int amx_int8 : 1;
int pclmulqdq : 1;
int smx : 1;
int sgx : 1;
int cx16 : 1; // aka. CMPXCHG16B
int sha : 1;
int popcnt : 1;
int movbe : 1;
int rdrnd : 1;
int dca : 1;
int ss : 1;
// Make sure to update X86FeaturesEnum below if you add a field here.
} X86Features;
typedef struct {
X86Features features;
int family;
int model;
int stepping;
char vendor[13]; // 0 terminated string
} X86Info;
// Calls cpuid and returns an initialized X86info.
// This function is guaranteed to be malloc, memset and memcpy free.
X86Info GetX86Info(void);
// Returns cache hierarchy informations.
// Can call cpuid multiple times.
// Only works on Intel CPU at the moment.
// This function is guaranteed to be malloc, memset and memcpy free.
CacheInfo GetX86CacheInfo(void);
typedef enum {
X86_UNKNOWN,
INTEL_CORE, // CORE
INTEL_PNR, // PENRYN
INTEL_NHM, // NEHALEM
INTEL_ATOM_BNL, // BONNELL
INTEL_WSM, // WESTMERE
INTEL_SNB, // SANDYBRIDGE
INTEL_IVB, // IVYBRIDGE
INTEL_ATOM_SMT, // SILVERMONT
INTEL_HSW, // HASWELL
INTEL_BDW, // BROADWELL
INTEL_SKL, // SKYLAKE
INTEL_ATOM_GMT, // GOLDMONT
INTEL_KBL, // KABY LAKE
INTEL_CFL, // COFFEE LAKE
INTEL_WHL, // WHISKEY LAKE
INTEL_CNL, // CANNON LAKE
INTEL_ICL, // ICE LAKE
INTEL_TGL, // TIGER LAKE
INTEL_SPR, // SAPPHIRE RAPIDS
AMD_HAMMER, // K8
AMD_K10, // K10
AMD_BOBCAT, // K14
AMD_BULLDOZER, // K15
AMD_JAGUAR, // K16
AMD_ZEN, // K17
} X86Microarchitecture;
// Returns the underlying microarchitecture by looking at X86Info's vendor,
// family and model.
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
// Calls cpuid and fills the brand_string.
// - brand_string *must* be of size 49 (beware of array decaying).
// - brand_string will be zero terminated.
// - This function calls memcpy.
void FillX86BrandString(char brand_string[49]);
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
typedef enum {
X86_FPU,
X86_TSC,
X86_CX8,
X86_CLFSH,
X86_MMX,
X86_AES,
X86_ERMS,
X86_F16C,
X86_FMA4,
X86_FMA3,
X86_VAES,
X86_VPCLMULQDQ,
X86_BMI1,
X86_HLE,
X86_BMI2,
X86_RTM,
X86_RDSEED,
X86_CLFLUSHOPT,
X86_CLWB,
X86_SSE,
X86_SSE2,
X86_SSE3,
X86_SSSE3,
X86_SSE4_1,
X86_SSE4_2,
X86_SSE4A,
X86_AVX,
X86_AVX2,
X86_AVX512F,
X86_AVX512CD,
X86_AVX512ER,
X86_AVX512PF,
X86_AVX512BW,
X86_AVX512DQ,
X86_AVX512VL,
X86_AVX512IFMA,
X86_AVX512VBMI,
X86_AVX512VBMI2,
X86_AVX512VNNI,
X86_AVX512BITALG,
X86_AVX512VPOPCNTDQ,
X86_AVX512_4VNNIW,
X86_AVX512_4VBMI2,
X86_AVX512_SECOND_FMA,
X86_AVX512_4FMAPS,
X86_AVX512_BF16,
X86_AVX512_VP2INTERSECT,
X86_AMX_BF16,
X86_AMX_TILE,
X86_AMX_INT8,
X86_PCLMULQDQ,
X86_SMX,
X86_SGX,
X86_CX16,
X86_SHA,
X86_POPCNT,
X86_MOVBE,
X86_RDRND,
X86_DCA,
X86_SS,
X86_LAST_,
} X86FeaturesEnum;
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
const char* GetX86MicroarchitectureName(X86Microarchitecture);
CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_X86)
#error "Including cpuinfo_x86.h from a non-x86 target."
#endif
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_

View File

@ -1,40 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
inline static bool IsBitSet(uint32_t reg, uint32_t bit) {
return (reg >> bit) & 0x1;
}
inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb,
uint32_t lsb) {
const uint64_t bits = msb - lsb + 1ULL;
const uint64_t mask = (1ULL << bits) - 1ULL;
assert(msb >= lsb);
return (reg >> lsb) & mask;
}
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_

View File

@ -1,37 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// A struct to hold the result of a call to cpuid.
typedef struct {
uint32_t eax, ebx, ecx, edx;
} Leaf;
// Returns the result of a call to the cpuid instruction.
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx);
// Returns the eax value of the XCR0 register.
uint32_t GetXCR0Eax(void);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_

View File

@ -1,39 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// An interface for the filesystem that allows mocking the filesystem in
// unittests.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
#include <stddef.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
int CpuFeatures_OpenFile(const char* filename);
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
// automatically on EINTR.
int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
// Same as linux "close(file_descriptor)".
void CpuFeatures_CloseFile(int file_descriptor);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_

View File

@ -1,186 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Interface to retrieve hardware capabilities. It relies on Linux's getauxval
// or `/proc/self/auxval` under the hood.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
#include <stdbool.h>
#include <stdint.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
// To avoid depending on the linux kernel we reproduce the architecture specific
// constants here.
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
#define AARCH64_HWCAP_FP (1UL << 0)
#define AARCH64_HWCAP_ASIMD (1UL << 1)
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
#define AARCH64_HWCAP_AES (1UL << 3)
#define AARCH64_HWCAP_PMULL (1UL << 4)
#define AARCH64_HWCAP_SHA1 (1UL << 5)
#define AARCH64_HWCAP_SHA2 (1UL << 6)
#define AARCH64_HWCAP_CRC32 (1UL << 7)
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
#define AARCH64_HWCAP_FPHP (1UL << 9)
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
#define AARCH64_HWCAP_CPUID (1UL << 11)
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
#define AARCH64_HWCAP_JSCVT (1UL << 13)
#define AARCH64_HWCAP_FCMA (1UL << 14)
#define AARCH64_HWCAP_LRCPC (1UL << 15)
#define AARCH64_HWCAP_DCPOP (1UL << 16)
#define AARCH64_HWCAP_SHA3 (1UL << 17)
#define AARCH64_HWCAP_SM3 (1UL << 18)
#define AARCH64_HWCAP_SM4 (1UL << 19)
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
#define AARCH64_HWCAP_SHA512 (1UL << 21)
#define AARCH64_HWCAP_SVE (1UL << 22)
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
#define AARCH64_HWCAP_DIT (1UL << 24)
#define AARCH64_HWCAP_USCAT (1UL << 25)
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
#define AARCH64_HWCAP_FLAGM (1UL << 27)
#define AARCH64_HWCAP_SSBS (1UL << 28)
#define AARCH64_HWCAP_SB (1UL << 29)
#define AARCH64_HWCAP_PACA (1UL << 30)
#define AARCH64_HWCAP_PACG (1UL << 31)
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
#define AARCH64_HWCAP2_FRINT (1UL << 8)
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
#define AARCH64_HWCAP2_I8MM (1UL << 13)
#define AARCH64_HWCAP2_BF16 (1UL << 14)
#define AARCH64_HWCAP2_DGH (1UL << 15)
#define AARCH64_HWCAP2_RNG (1UL << 16)
#define AARCH64_HWCAP2_BTI (1UL << 17)
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
#define ARM_HWCAP_SWP (1UL << 0)
#define ARM_HWCAP_HALF (1UL << 1)
#define ARM_HWCAP_THUMB (1UL << 2)
#define ARM_HWCAP_26BIT (1UL << 3)
#define ARM_HWCAP_FAST_MULT (1UL << 4)
#define ARM_HWCAP_FPA (1UL << 5)
#define ARM_HWCAP_VFP (1UL << 6)
#define ARM_HWCAP_EDSP (1UL << 7)
#define ARM_HWCAP_JAVA (1UL << 8)
#define ARM_HWCAP_IWMMXT (1UL << 9)
#define ARM_HWCAP_CRUNCH (1UL << 10)
#define ARM_HWCAP_THUMBEE (1UL << 11)
#define ARM_HWCAP_NEON (1UL << 12)
#define ARM_HWCAP_VFPV3 (1UL << 13)
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
#define ARM_HWCAP_TLS (1UL << 15)
#define ARM_HWCAP_VFPV4 (1UL << 16)
#define ARM_HWCAP_IDIVA (1UL << 17)
#define ARM_HWCAP_IDIVT (1UL << 18)
#define ARM_HWCAP_VFPD32 (1UL << 19)
#define ARM_HWCAP_LPAE (1UL << 20)
#define ARM_HWCAP_EVTSTRM (1UL << 21)
#define ARM_HWCAP2_AES (1UL << 0)
#define ARM_HWCAP2_PMULL (1UL << 1)
#define ARM_HWCAP2_SHA1 (1UL << 2)
#define ARM_HWCAP2_SHA2 (1UL << 3)
#define ARM_HWCAP2_CRC32 (1UL << 4)
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
#define MIPS_HWCAP_R6 (1UL << 0)
#define MIPS_HWCAP_MSA (1UL << 1)
#define MIPS_HWCAP_CRC32 (1UL << 2)
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
/* in AT_HWCAP */
#define PPC_FEATURE_32 0x80000000
#define PPC_FEATURE_64 0x40000000
#define PPC_FEATURE_601_INSTR 0x20000000
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_FPU 0x08000000
#define PPC_FEATURE_HAS_MMU 0x04000000
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
#define PPC_FEATURE_HAS_SPE 0x00800000
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
#define PPC_FEATURE_NO_TB 0x00100000
#define PPC_FEATURE_POWER4 0x00080000
#define PPC_FEATURE_POWER5 0x00040000
#define PPC_FEATURE_POWER5_PLUS 0x00020000
#define PPC_FEATURE_CELL 0x00010000
#define PPC_FEATURE_BOOKE 0x00008000
#define PPC_FEATURE_SMT 0x00004000
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
#define PPC_FEATURE_ARCH_2_05 0x00001000
#define PPC_FEATURE_PA6T 0x00000800
#define PPC_FEATURE_HAS_DFP 0x00000400
#define PPC_FEATURE_POWER6_EXT 0x00000200
#define PPC_FEATURE_ARCH_2_06 0x00000100
#define PPC_FEATURE_HAS_VSX 0x00000080
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
/* Reserved - do not use 0x00000004 */
#define PPC_FEATURE_TRUE_LE 0x00000002
#define PPC_FEATURE_PPC_LE 0x00000001
/* in AT_HWCAP2 */
#define PPC_FEATURE2_ARCH_2_07 0x80000000
#define PPC_FEATURE2_HTM 0x40000000
#define PPC_FEATURE2_DSCR 0x20000000
#define PPC_FEATURE2_EBB 0x10000000
#define PPC_FEATURE2_ISEL 0x08000000
#define PPC_FEATURE2_TAR 0x04000000
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#define PPC_FEATURE2_HTM_NOSC 0x01000000
#define PPC_FEATURE2_ARCH_3_00 0x00800000
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
#define PPC_FEATURE2_DARN 0x00200000
#define PPC_FEATURE2_SCV 0x00100000
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
#endif
typedef struct {
unsigned long hwcaps;
unsigned long hwcaps2;
} HardwareCapabilities;
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps);
typedef struct {
char platform[64]; // 0 terminated string
char base_platform[64]; // 0 terminated string
} PlatformType;
PlatformType CpuFeatures_GetPlatformType(void);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_

View File

@ -1,49 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Reads a file line by line and stores the data on the stack. This allows
// parsing files in one go without allocating.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
#include <stdbool.h>
#include "cpu_features_macros.h"
#include "internal/string_view.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
char buffer[STACK_LINE_READER_BUFFER_SIZE];
StringView view;
int fd;
bool skip_mode;
} StackLineReader;
// Initializes a StackLineReader.
void StackLineReader_Initialize(StackLineReader* reader, int fd);
typedef struct {
StringView line; // A view of the line.
bool eof; // Nothing more to read, we reached EOF.
bool full_line; // If false the line was truncated to
// STACK_LINE_READER_BUFFER_SIZE.
} LineResult;
// Reads the file pointed to by fd and tries to read a full line.
LineResult StackLineReader_NextLine(StackLineReader* reader);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_

View File

@ -1,109 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// A view over a piece of string. The view is not 0 terminated.
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "cpu_features_macros.h"
CPU_FEATURES_START_CPP_NAMESPACE
typedef struct {
const char* ptr;
size_t size;
} StringView;
#ifdef __cplusplus
static const StringView kEmptyStringView = {NULL, 0};
#else
static const StringView kEmptyStringView;
#endif
// Returns a StringView from the provided string.
// Passing NULL is valid only if size is 0.
static inline StringView view(const char* str, const size_t size) {
StringView view;
view.ptr = str;
view.size = size;
return view;
}
static inline StringView str(const char* str) { return view(str, strlen(str)); }
// Returns the index of the first occurrence of c in view or -1 if not found.
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
// Returns the index of the first occurrence of sub_view in view or -1 if not
// found.
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view);
// Returns whether a is equal to b (same content).
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
// Returns whether a starts with b.
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
// Removes count characters from the beginning of view or kEmptyStringView if
// count if greater than view.size.
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count);
// Removes count characters from the end of view or kEmptyStringView if count if
// greater than view.size.
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count);
// Keeps the count first characters of view or view if count if greater than
// view.size.
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count);
// Retrieves the first character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Front(const StringView view);
// Retrieves the last character of view. If view is empty the behavior is
// undefined.
char CpuFeatures_StringView_Back(const StringView view);
// Removes leading and tailing space characters.
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
// Convert StringView to positive integer. e.g. "42", "0x2a".
// Returns -1 on error.
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
// Copies src StringView to dst buffer.
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size);
// Checks if line contains the specified whitespace separated word.
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word);
// Get key/value from line. key and value are separated by ": ".
// key and value are cleaned up from leading and trailing whitespaces.
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value);
CPU_FEATURES_END_CPP_NAMESPACE
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_

View File

@ -1,60 +0,0 @@
#
# library : NDK compat
#
find_package(Threads REQUIRED)
set (NDK_COMPAT_HDRS cpu-features.h)
set (NDK_COMPAT_SRCS
cpu-features.c
$<TARGET_OBJECTS:utils>
$<TARGET_OBJECTS:unix_based_hardware_detection>
)
# Note that following `add_cpu_features_headers_and_sources` will use
# NDK_COMPAT_SRCS in lieu of NDK_COMPAT_HDRS because we don't want cpu_features
# headers to be installed alongside ndk_compat.
add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS)
add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS})
setup_include_and_definitions(ndk_compat)
target_include_directories(ndk_compat PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}")
include(GNUInstallDirs)
install(TARGETS ndk_compat
EXPORT CpuFeaturesNdkCompatTargets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ndk_compat
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(EXPORT CpuFeaturesNdkCompatTargets
NAMESPACE CpuFeatures::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat
COMPONENT Devel
)
include(CMakePackageConfigHelpers)
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/CpuFeaturesNdkCompatConfig.cmake.in
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
)
install(
FILES
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
COMPONENT Devel
)
#
# program : NDK compat test program
#
if(ENABLE_TESTING)
add_executable(ndk-compat-test ndk-compat-test.c)
target_link_libraries(ndk-compat-test PRIVATE ndk_compat)
endif()

View File

@ -1,4 +0,0 @@
Provides a header compatible with [android's NDK cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h).
It is intended to be a drop in replacement for this header and help users
transition from the NDK to [Google's cpu_features library](https://github.com/google/cpu_features).

View File

@ -1,205 +0,0 @@
#include "cpu-features.h"
#include <pthread.h>
#include "cpu_features_macros.h"
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
#if defined(CPU_FEATURES_ARCH_ARM)
#include "cpuinfo_arm.h"
#elif defined(CPU_FEATURES_ARCH_X86)
#include "cpuinfo_x86.h"
#elif defined(CPU_FEATURES_ARCH_MIPS)
#include "cpuinfo_mips.h"
#elif defined(CPU_FEATURES_ARCH_AARCH64)
#include "cpuinfo_aarch64.h"
#endif
static pthread_once_t g_once;
static int g_inited;
static uint64_t g_cpuFeatures;
static int g_cpuCount;
#ifdef CPU_FEATURES_ARCH_ARM
static uint32_t g_cpuIdArm;
#endif
static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) {
*cpu_mask |= 1UL << index;
}
// Examples of valid inputs: "31", "4-31"
static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) {
int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-');
if (separator_index < 0) { // A single cpu index
int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text);
if (cpu_index < 0) return;
set_cpu_mask_bit(cpu_index, cpu_mask);
} else {
int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber(
CpuFeatures_StringView_KeepFront(text, separator_index));
int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber(
CpuFeatures_StringView_PopFront(text, separator_index + 1));
int i;
if (cpu_index_a < 0 || cpu_index_b < 0) return;
for (i = cpu_index_a; i <= cpu_index_b; ++i) {
if (i < 32) {
set_cpu_mask_bit(i, cpu_mask);
}
}
}
}
// Format specification from
// https://www.kernel.org/doc/Documentation/cputopology.txt
// Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3"
static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) {
if (!result.full_line || result.eof) return;
StringView line = result.line;
for (; line.size > 0;) {
int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ',');
if (next_entry_index < 0) {
parse_cpu_mask(line, cpu_mask);
break;
}
StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index);
parse_cpu_mask(entry, cpu_mask);
line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1);
}
}
static void update_cpu_mask_from_file(const char* filename,
uint32_t* cpu_mask) {
const int fd = CpuFeatures_OpenFile(filename);
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask);
CpuFeatures_CloseFile(fd);
}
}
static int get_cpu_count(void) {
uint32_t cpu_mask = 0;
update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask);
update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask);
return __builtin_popcount(cpu_mask);
}
static void android_cpuInit(void) {
g_cpuFeatures = 0;
g_cpuCount = 1;
g_inited = 1;
g_cpuCount = get_cpu_count();
if (g_cpuCount == 0) {
g_cpuCount = 1;
}
#if defined(CPU_FEATURES_ARCH_ARM)
ArmInfo info = GetArmInfo();
if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
if (info.features.neon) {
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32;
}
if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16;
if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
if (info.architecture >= 6)
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
if (info.features.vfpv4) {
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA;
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
}
g_cpuIdArm = GetArmCpuId(&info);
#elif defined(CPU_FEATURES_ARCH_X86)
X86Info info = GetX86Info();
if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
#elif defined(CPU_FEATURES_ARCH_MIPS)
MipsInfo info = GetMipsInfo();
if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
#elif defined(CPU_FEATURES_ARCH_AARCH64)
Aarch64Info info = GetAarch64Info();
if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
#endif
}
AndroidCpuFamily android_getCpuFamily(void) {
#if defined(CPU_FEATURES_ARCH_ARM)
return ANDROID_CPU_FAMILY_ARM;
#elif defined(CPU_FEATURES_ARCH_X86_32)
return ANDROID_CPU_FAMILY_X86;
#elif defined(CPU_FEATURES_ARCH_MIPS64)
return ANDROID_CPU_FAMILY_MIPS64;
#elif defined(CPU_FEATURES_ARCH_MIPS32)
return ANDROID_CPU_FAMILY_MIPS;
#elif defined(CPU_FEATURES_ARCH_AARCH64)
return ANDROID_CPU_FAMILY_ARM64;
#elif defined(CPU_FEATURES_ARCH_X86_64)
return ANDROID_CPU_FAMILY_X86_64;
#else
return ANDROID_CPU_FAMILY_UNKNOWN;
#endif
}
uint64_t android_getCpuFeatures(void) {
pthread_once(&g_once, android_cpuInit);
return g_cpuFeatures;
}
int android_getCpuCount(void) {
pthread_once(&g_once, android_cpuInit);
return g_cpuCount;
}
static void android_cpuInitDummy(void) { g_inited = 1; }
int android_setCpu(int cpu_count, uint64_t cpu_features) {
/* Fail if the library was already initialized. */
if (g_inited) return 0;
g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
g_cpuFeatures = cpu_features;
pthread_once(&g_once, android_cpuInitDummy);
return 1;
}
#ifdef CPU_FEATURES_ARCH_ARM
uint32_t android_getCpuIdArm(void) {
pthread_once(&g_once, android_cpuInit);
return g_cpuIdArm;
}
int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) {
if (!android_setCpu(cpu_count, cpu_features)) return 0;
g_cpuIdArm = cpu_id;
return 1;
}
#endif // CPU_FEATURES_ARCH_ARM

View File

@ -1,320 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef GOOGLE_CPU_FEATURES_H
#define GOOGLE_CPU_FEATURES_H
#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
/* A list of valid values returned by android_getCpuFamily().
* They describe the CPU Architecture of the current process.
*/
typedef enum {
ANDROID_CPU_FAMILY_UNKNOWN = 0,
ANDROID_CPU_FAMILY_ARM,
ANDROID_CPU_FAMILY_X86,
ANDROID_CPU_FAMILY_MIPS,
ANDROID_CPU_FAMILY_ARM64,
ANDROID_CPU_FAMILY_X86_64,
ANDROID_CPU_FAMILY_MIPS64,
ANDROID_CPU_FAMILY_MAX /* do not remove */
} AndroidCpuFamily;
/* Return the CPU family of the current process.
*
* Note that this matches the bitness of the current process. I.e. when
* running a 32-bit binary on a 64-bit capable CPU, this will return the
* 32-bit CPU family value.
*/
extern AndroidCpuFamily android_getCpuFamily(void);
/* Return a bitmap describing a set of optional CPU features that are
* supported by the current device's CPU. The exact bit-flags returned
* depend on the value returned by android_getCpuFamily(). See the
* documentation for the ANDROID_CPU_*_FEATURE_* flags below for details.
*/
extern uint64_t android_getCpuFeatures(void);
/* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be
* recognized by the library (see note below for 64-bit ARM). Value details
* are:
*
* VFPv2:
* CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs
* support these instructions. VFPv2 is a subset of VFPv3 so this will
* be set whenever VFPv3 is set too.
*
* ARMv7:
* CPU supports the ARMv7-A basic instruction set.
* This feature is mandated by the 'armeabi-v7a' ABI.
*
* VFPv3:
* CPU supports the VFPv3-D16 instruction set, providing hardware FPU
* support for single and double precision floating point registers.
* Note that only 16 FPU registers are available by default, unless
* the D32 bit is set too. This feature is also mandated by the
* 'armeabi-v7a' ABI.
*
* VFP_D32:
* CPU VFP optional extension that provides 32 FPU registers,
* instead of 16. Note that ARM mandates this feature is the 'NEON'
* feature is implemented by the CPU.
*
* NEON:
* CPU FPU supports "ARM Advanced SIMD" instructions, also known as
* NEON. Note that this mandates the VFP_D32 feature as well, per the
* ARM Architecture specification.
*
* VFP_FP16:
* Half-width floating precision VFP extension. If set, the CPU
* supports instructions to perform floating-point operations on
* 16-bit registers. This is part of the VFPv4 specification, but
* not mandated by any Android ABI.
*
* VFP_FMA:
* Fused multiply-accumulate VFP instructions extension. Also part of
* the VFPv4 specification, but not mandated by any Android ABI.
*
* NEON_FMA:
* Fused multiply-accumulate NEON instructions extension. Optional
* extension from the VFPv4 specification, but not mandated by any
* Android ABI.
*
* IDIV_ARM:
* Integer division available in ARM mode. Only available
* on recent CPUs (e.g. Cortex-A15).
*
* IDIV_THUMB2:
* Integer division available in Thumb-2 mode. Only available
* on recent CPUs (e.g. Cortex-A15).
*
* iWMMXt:
* Optional extension that adds MMX registers and operations to an
* ARM CPU. This is only available on a few XScale-based CPU designs
* sold by Marvell. Pretty rare in practice.
*
* AES:
* CPU supports AES instructions. These instructions are only
* available for 32-bit applications running on ARMv8 CPU.
*
* CRC32:
* CPU supports CRC32 instructions. These instructions are only
* available for 32-bit applications running on ARMv8 CPU.
*
* SHA2:
* CPU supports SHA2 instructions. These instructions are only
* available for 32-bit applications running on ARMv8 CPU.
*
* SHA1:
* CPU supports SHA1 instructions. These instructions are only
* available for 32-bit applications running on ARMv8 CPU.
*
* PMULL:
* CPU supports 64-bit PMULL and PMULL2 instructions. These
* instructions are only available for 32-bit applications
* running on ARMv8 CPU.
*
* If you want to tell the compiler to generate code that targets one of
* the feature set above, you should probably use one of the following
* flags (for more details, see technical note at the end of this file):
*
* -mfpu=vfp
* -mfpu=vfpv2
* These are equivalent and tell GCC to use VFPv2 instructions for
* floating-point operations. Use this if you want your code to
* run on *some* ARMv6 devices, and any ARMv7-A device supported
* by Android.
*
* Generated code requires VFPv2 feature.
*
* -mfpu=vfpv3-d16
* Tell GCC to use VFPv3 instructions (using only 16 FPU registers).
* This should be generic code that runs on any CPU that supports the
* 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this.
*
* Generated code requires VFPv3 feature.
*
* -mfpu=vfpv3
* Tell GCC to use VFPv3 instructions with 32 FPU registers.
* Generated code requires VFPv3|VFP_D32 features.
*
* -mfpu=neon
* Tell GCC to use VFPv3 instructions with 32 FPU registers, and
* also support NEON intrinsics (see <arm_neon.h>).
* Generated code requires VFPv3|VFP_D32|NEON features.
*
* -mfpu=vfpv4-d16
* Generated code requires VFPv3|VFP_FP16|VFP_FMA features.
*
* -mfpu=vfpv4
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features.
*
* -mfpu=neon-vfpv4
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA
* features.
*
* -mcpu=cortex-a7
* -mcpu=cortex-a15
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|
* NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2
* This flag implies -mfpu=neon-vfpv4.
*
* -mcpu=iwmmxt
* Allows the use of iWMMXt instrinsics with GCC.
*
* IMPORTANT NOTE: These flags should only be tested when
* android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a
* 32-bit process.
*
* When running a 64-bit ARM process on an ARMv8 CPU,
* android_getCpuFeatures() will return a different set of bitflags
*/
enum {
ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4),
ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5),
ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6),
ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7),
ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8),
ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9),
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10),
ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11),
ANDROID_CPU_ARM_FEATURE_AES = (1 << 12),
ANDROID_CPU_ARM_FEATURE_PMULL = (1 << 13),
ANDROID_CPU_ARM_FEATURE_SHA1 = (1 << 14),
ANDROID_CPU_ARM_FEATURE_SHA2 = (1 << 15),
ANDROID_CPU_ARM_FEATURE_CRC32 = (1 << 16),
};
/* The bit flags corresponding to the output of android_getCpuFeatures()
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details
* are:
*
* FP:
* CPU has Floating-point unit.
*
* ASIMD:
* CPU has Advanced SIMD unit.
*
* AES:
* CPU supports AES instructions.
*
* CRC32:
* CPU supports CRC32 instructions.
*
* SHA2:
* CPU supports SHA2 instructions.
*
* SHA1:
* CPU supports SHA1 instructions.
*
* PMULL:
* CPU supports 64-bit PMULL and PMULL2 instructions.
*/
enum {
ANDROID_CPU_ARM64_FEATURE_FP = (1 << 0),
ANDROID_CPU_ARM64_FEATURE_ASIMD = (1 << 1),
ANDROID_CPU_ARM64_FEATURE_AES = (1 << 2),
ANDROID_CPU_ARM64_FEATURE_PMULL = (1 << 3),
ANDROID_CPU_ARM64_FEATURE_SHA1 = (1 << 4),
ANDROID_CPU_ARM64_FEATURE_SHA2 = (1 << 5),
ANDROID_CPU_ARM64_FEATURE_CRC32 = (1 << 6),
};
/* The bit flags corresponding to the output of android_getCpuFeatures()
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or
* ANDROID_CPU_FAMILY_X86_64.
*/
enum {
ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3),
ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4),
ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5),
ANDROID_CPU_X86_FEATURE_AVX = (1 << 6),
ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7),
ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8),
ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9),
};
/* The bit flags corresponding to the output of android_getCpuFeatures()
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS
* or ANDROID_CPU_FAMILY_MIPS64. Values are:
*
* R6:
* CPU executes MIPS Release 6 instructions natively, and
* supports obsoleted R1..R5 instructions only via kernel traps.
*
* MSA:
* CPU supports Mips SIMD Architecture instructions.
*/
enum {
ANDROID_CPU_MIPS_FEATURE_R6 = (1 << 0),
ANDROID_CPU_MIPS_FEATURE_MSA = (1 << 1),
};
/* Return the number of CPU cores detected on this device.
* Please note the current implementation supports up to 32 cpus.
*/
extern int android_getCpuCount(void);
/* The following is used to force the CPU count and features
* mask in sandboxed processes. Under 4.1 and higher, these processes
* cannot access /proc, which is the only way to get information from
* the kernel about the current hardware (at least on ARM).
*
* It _must_ be called only once, and before any android_getCpuXXX
* function, any other case will fail.
*
* This function return 1 on success, and 0 on failure.
*/
extern int android_setCpu(int cpu_count, uint64_t cpu_features);
#ifdef __arm__
/* Retrieve the ARM 32-bit CPUID value from the kernel.
* Note that this cannot work on sandboxed processes under 4.1 and
* higher, unless you called android_setCpuArm() before.
*/
extern uint32_t android_getCpuIdArm(void);
/* An ARM-specific variant of android_setCpu() that also allows you
* to set the ARM CPUID field.
*/
extern int android_setCpuArm(int cpu_count, uint64_t cpu_features,
uint32_t cpu_id);
#endif
__END_DECLS
#endif /* GOOGLE_CPU_FEATURES_H */

View File

@ -1,12 +0,0 @@
#include <stdio.h>
#include "cpu-features.h"
int main() {
printf("android_getCpuFamily()=%d\n", android_getCpuFamily());
printf("android_getCpuFeatures()=0x%08llx\n", android_getCpuFeatures());
printf("android_getCpuCount()=%d\n", android_getCpuCount());
#ifdef __arm__
printf("android_getCpuIdArm()=0x%04x\n", android_getCpuIdArm());
#endif //__arm__
}

View File

@ -1,209 +0,0 @@
#!/usr/bin/env bash
readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
readonly PROJECT_FOLDER="${SCRIPT_FOLDER}/.."
readonly ARCHIVE_FOLDER=~/cpu_features_archives
readonly QEMU_INSTALL=${ARCHIVE_FOLDER}/qemu
readonly DEFAULT_CMAKE_ARGS=" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON"
function extract() {
case $1 in
*.tar.bz2) tar xjf "$1" ;;
*.tar.xz) tar xJf "$1" ;;
*.tar.gz) tar xzf "$1" ;;
*)
echo "don't know how to extract '$1'..."
exit 1
esac
}
function unpackifnotexists() {
mkdir -p "${ARCHIVE_FOLDER}"
cd "${ARCHIVE_FOLDER}" || exit
local URL=$1
local RELATIVE_FOLDER=$2
local DESTINATION="${ARCHIVE_FOLDER}/${RELATIVE_FOLDER}"
if [[ ! -d "${DESTINATION}" ]] ; then
local ARCHIVE_NAME=$(echo ${URL} | sed 's/.*\///')
test -f "${ARCHIVE_NAME}" || wget -q "${URL}"
extract "${ARCHIVE_NAME}"
rm -f "${ARCHIVE_NAME}"
fi
}
function installqemuifneeded() {
local VERSION=${QEMU_VERSION:=2.11.1}
local ARCHES=${QEMU_ARCHES:=arm aarch64 i386 x86_64 mips mipsel mips64 mips64el}
local TARGETS=${QEMU_TARGETS:=$(echo "$ARCHES" | sed 's#$# #;s#\([^ ]*\) #\1-linux-user #g')}
if echo "${VERSION} ${TARGETS}" | cmp --silent ${QEMU_INSTALL}/.build -; then
echo "qemu ${VERSION} up to date!"
return 0
fi
echo "VERSION: ${VERSION}"
echo "TARGETS: ${TARGETS}"
rm -rf ${QEMU_INSTALL}
# Checking for a tarball before downloading makes testing easier :-)
local QEMU_URL="http://wiki.qemu-project.org/download/qemu-${VERSION}.tar.xz"
local QEMU_FOLDER="qemu-${VERSION}"
unpackifnotexists ${QEMU_URL} ${QEMU_FOLDER}
cd ${QEMU_FOLDER} || exit
./configure \
--prefix="${QEMU_INSTALL}" \
--target-list="${TARGETS}" \
--disable-docs \
--disable-sdl \
--disable-gtk \
--disable-gnutls \
--disable-gcrypt \
--disable-nettle \
--disable-curses \
--static
make -j4
make install
echo "$VERSION $TARGETS" > ${QEMU_INSTALL}/.build
}
function assert_defined(){
local VALUE=${1}
: "${VALUE?"${1} needs to be defined"}"
}
function integrate() {
cd "${PROJECT_FOLDER}"
case "${OS}" in
"Windows_NT") CMAKE_BUILD_ARGS="--config Debug --target ALL_BUILD"
CMAKE_TEST_FILES="${BUILD_DIR}/test/Debug/*_test.exe"
DEMO=${BUILD_DIR}/Debug/list_cpu_features.exe
;;
*) CMAKE_BUILD_ARGS="--target all"
CMAKE_TEST_FILES="${BUILD_DIR}/test/*_test"
DEMO=${BUILD_DIR}/list_cpu_features
;;
esac
# Generating CMake configuration
cmake -H. -B"${BUILD_DIR}" ${DEFAULT_CMAKE_ARGS} "${CMAKE_ADDITIONAL_ARGS[@]}" -G"${CMAKE_GENERATOR:-Unix Makefiles}"
# Building
cmake --build "${BUILD_DIR}" ${CMAKE_BUILD_ARGS}
# Running tests if needed
if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
return
fi
RUN_CMD=""
if [[ -n "${QEMU_ARCH}" ]]; then
installqemuifneeded
RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[@]}"
fi
for test_binary in ${CMAKE_TEST_FILES}; do
${RUN_CMD} ${test_binary}
done
${RUN_CMD} ${DEMO}
}
function expand_linaro_config() {
assert_defined TARGET
local LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11
local GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}.tar.xz
local GCC_RELATIVE_FOLDER="gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}"
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
local SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-2.25-2017.11-${TARGET}.tar.xz
local SYSROOT_RELATIVE_FOLDER=sysroot-glibc-linaro-2.25-2017.11-${TARGET}
unpackifnotexists "${SYSROOT_URL}" "${SYSROOT_RELATIVE_FOLDER}"
local SYSROOT_FOLDER=${ARCHIVE_FOLDER}/${SYSROOT_RELATIVE_FOLDER}
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSROOT=${SYSROOT_FOLDER})
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=${GCC_FOLDER}/bin/${TARGET}-gcc)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=${GCC_FOLDER}/bin/${TARGET}-g++)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY)
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
QEMU_ARGS+=(-E LD_LIBRARY_PATH=/lib)
}
function expand_codescape_config() {
assert_defined TARGET
local DATE=2017.10-08
local CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz
local GCC_URL=${CODESCAPE_URL}
local GCC_RELATIVE_FOLDER="mips-mti-linux-gnu/${DATE}"
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
local MIPS_FLAGS=""
local LIBC_FOLDER_SUFFIX=""
local FLAVOUR=""
case "${TARGET}" in
"mips32") MIPS_FLAGS="-EB -mabi=32"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
"mips32el") MIPS_FLAGS="-EL -mabi=32"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
"mips64") MIPS_FLAGS="-EB -mabi=64"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
"mips64el") MIPS_FLAGS="-EL -mabi=64"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
*) echo 'unknown mips platform'; exit 1;;
esac
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH=${GCC_FOLDER})
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=mips-mti-linux-gnu-gcc)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=mips-mti-linux-gnu-g++)
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER_ARG1="${MIPS_FLAGS}")
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER_ARG1="${MIPS_FLAGS}")
local SYSROOT_FOLDER=${GCC_FOLDER}/sysroot/${FLAVOUR}
# Keeping only the sysroot of interest to save on travis cache.
if [[ "${CONTINUOUS_INTEGRATION}" = "true" ]]; then
for folder in ${GCC_FOLDER}/sysroot/*; do
if [[ "${folder}" != "${SYSROOT_FOLDER}" ]]; then
rm -rf ${folder}
fi
done
fi
local LIBC_FOLDER=${GCC_FOLDER}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_FOLDER_SUFFIX}
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
QEMU_ARGS+=(-E LD_PRELOAD=${LIBC_FOLDER}/libstdc++.so.6:${LIBC_FOLDER}/libgcc_s.so.1)
}
function expand_environment_and_integrate() {
assert_defined PROJECT_FOLDER
assert_defined TARGET
BUILD_DIR="${PROJECT_FOLDER}/cmake_build/${TARGET}"
mkdir -p "${BUILD_DIR}"
declare -a CONFIG_NAMES=()
declare -a QEMU_ARGS=()
declare -a CMAKE_ADDITIONAL_ARGS=()
case ${TOOLCHAIN} in
LINARO) expand_linaro_config ;;
CODESCAPE) expand_codescape_config ;;
NATIVE) QEMU_ARCH="" ;;
*) echo "Unknown toolchain '${TOOLCHAIN}'..."; exit 1;;
esac
integrate
}
if [ "${CONTINUOUS_INTEGRATION}" = "true" ]; then
QEMU_ARCHES=${QEMU_ARCH}
expand_environment_and_integrate
fi

View File

@ -1,106 +0,0 @@
#!/usr/bin/env bash
source "$(dirname -- "$0")"/run_integration.sh
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
function set_aarch64-linux-gnu() {
TOOLCHAIN=LINARO
TARGET=aarch64-linux-gnu
QEMU_ARCH=aarch64
}
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_arm-linux-gnueabihf() {
TOOLCHAIN=LINARO
TARGET=arm-linux-gnueabihf
QEMU_ARCH=arm
}
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
function set_armv8l-linux-gnueabihf() {
TOOLCHAIN=LINARO
TARGET=armv8l-linux-gnueabihf
QEMU_ARCH=arm
}
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_arm-linux-gnueabi() {
TOOLCHAIN=LINARO
TARGET=arm-linux-gnueabi
QEMU_ARCH=arm
}
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
function set_aarch64_be-linux-gnu() {
TOOLCHAIN=LINARO
TARGET=aarch64_be-linux-gnu
QEMU_ARCH=DISABLED
}
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_armeb-linux-gnueabihf() {
TOOLCHAIN=LINARO
TARGET=armeb-linux-gnueabihf
QEMU_ARCH=DISABLED
}
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
function set_armeb-linux-gnueabi() {
TOOLCHAIN=LINARO
TARGET=armeb-linux-gnueabi
QEMU_ARCH=DISABLED
}
function set_mips32() {
TOOLCHAIN=CODESCAPE
TARGET=mips32
QEMU_ARCH=mips
}
function set_mips32el() {
TOOLCHAIN=CODESCAPE
TARGET=mips32el
QEMU_ARCH=mipsel
}
function set_mips64() {
TOOLCHAIN=CODESCAPE
TARGET=mips64
QEMU_ARCH=mips64
}
function set_mips64el() {
TOOLCHAIN=CODESCAPE
TARGET=mips64el
QEMU_ARCH=mips64el
}
function set_native() {
TOOLCHAIN=NATIVE
TARGET=native
QEMU_ARCH=""
}
ENVIRONMENTS="
set_aarch64-linux-gnu
set_arm-linux-gnueabihf
set_armv8l-linux-gnueabihf
set_arm-linux-gnueabi
set_aarch64_be-linux-gnu
set_armeb-linux-gnueabihf
set_armeb-linux-gnueabi
set_mips32
set_mips32el
set_mips64
set_mips64el
set_native
"
set -e
CMAKE_GENERATOR="Ninja"
for SET_ENVIRONMENT in ${ENVIRONMENTS}; do
${SET_ENVIRONMENT}
expand_environment_and_integrate
done

View File

@ -1,150 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_aarch64.h"
#include <assert.h>
#include <ctype.h>
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
AARCH64_HWCAP2_SVEBITPERM) \
FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)
#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features
#include "define_tables.h"
static bool HandleAarch64Line(const LineResult result,
Aarch64Info* const info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
kSetters[i](&info->features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
}
}
return !result.eof;
}
static void FillProcCpuInfoData(Aarch64Info* const info) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const Aarch64Info kEmptyAarch64Info;
Aarch64Info GetAarch64Info(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
Aarch64Info info = kEmptyAarch64Info;
FillProcCpuInfoData(&info);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
Aarch64FeaturesEnum value) {
if (value >= AARCH64_LAST_) return false;
return kGetters[value](features);
}
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
if (value >= AARCH64_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,212 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_arm.h"
#include <assert.h>
#include <ctype.h>
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures
#include "define_tables.h"
typedef struct {
bool processor_reports_armv6;
bool hardware_reports_goldfish;
} ProcCpuInfoData;
static int IndexOfNonDigit(StringView str) {
size_t index = 0;
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
str = CpuFeatures_StringView_PopFront(str, 1);
++index;
}
return index;
}
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
ProcCpuInfoData* const proc_info) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
for (size_t i = 0; i < ARM_LAST_; ++i) {
kSetters[i](&info->features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
// CPU architecture is a number that may be followed by letters. e.g.
// "6TEJ", "7".
const StringView digits =
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
CpuFeatures_StringView_IsEquals(key, str("model name"))) {
// Android reports this in a non-Linux standard "Processor" but sometimes
// also in "model name", Linux reports it only in "model name"
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
proc_info->processor_reports_armv6 =
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
proc_info->hardware_reports_goldfish =
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
}
}
return !result.eof;
}
uint32_t GetArmCpuId(const ArmInfo* const info) {
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
(ExtractBitRange(info->variant, 3, 0) << 20) |
(ExtractBitRange(info->part, 11, 0) << 4) |
(ExtractBitRange(info->revision, 3, 0) << 0);
}
static void FixErrors(ArmInfo* const info,
ProcCpuInfoData* const proc_cpu_info_data) {
// Fixing Samsung kernel reporting invalid cpu architecture.
// http://code.google.com/p/android/issues/detail?id=10812
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
info->architecture = 6;
}
// Handle kernel configuration bugs that prevent the correct reporting of CPU
// features.
switch (GetArmCpuId(info)) {
case 0x4100C080:
// Special case: The emulator-specific Android 4.2 kernel fails to report
// support for the 32-bit ARM IDIV instruction. Technically, this is a
// feature of the virtual CPU implemented by the emulator. Note that it
// could also support Thumb IDIV in the future, and this will have to be
// slightly updated.
if (info->architecture >= 7 &&
proc_cpu_info_data->hardware_reports_goldfish) {
info->features.idiva = true;
}
break;
case 0x511004D0:
// https://crbug.com/341598.
info->features.neon = false;
break;
case 0x510006F2:
case 0x510006F3:
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
// IDIV support.
info->features.idiva = true;
info->features.idivt = true;
break;
}
// Propagate cpu features.
if (info->features.vfpv4) info->features.vfpv3 = true;
if (info->features.neon) info->features.vfpv3 = true;
if (info->features.vfpv3) info->features.vfp = true;
}
static void FillProcCpuInfoData(ArmInfo* const info,
ProcCpuInfoData* proc_cpu_info_data) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
proc_cpu_info_data)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const ArmInfo kEmptyArmInfo;
static const ProcCpuInfoData kEmptyProcCpuInfoData;
ArmInfo GetArmInfo(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
ArmInfo info = kEmptyArmInfo;
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
FillProcCpuInfoData(&info, &proc_cpu_info_data);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < ARM_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
FixErrors(&info, &proc_cpu_info_data);
return info;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetArmFeaturesEnumValue(const ArmFeatures* features,
ArmFeaturesEnum value) {
if (value >= ARM_LAST_) return false;
return kGetters[value](features);
}
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
if (value >= ARM_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,92 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_mips.h"
#include <assert.h>
#include "internal/filesystem.h"
#include "internal/hwcaps.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
FEATURE(MIPS_EVA, eva, "eva", 0, 0) \
FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures
#include "define_tables.h"
static bool HandleMipsLine(const LineResult result,
MipsFeatures* const features) {
StringView key, value;
// See tests for an example.
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
for (size_t i = 0; i < MIPS_LAST_; ++i) {
kSetters[i](features,
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
}
}
}
return !result.eof;
}
static void FillProcCpuInfoData(MipsFeatures* const features) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const MipsInfo kEmptyMipsInfo;
MipsInfo GetMipsInfo(void) {
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
// have some information if the executable is sandboxed (aka no access to
// /proc/cpuinfo).
MipsInfo info = kEmptyMipsInfo;
FillProcCpuInfoData(&info.features);
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < MIPS_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
MipsFeaturesEnum value) {
if (value >= MIPS_LAST_) return false;
return kGetters[value](features);
}
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
if (value >= MIPS_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

View File

@ -1,154 +0,0 @@
// Copyright 2018 IBM.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_ppc.h"
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "internal/bit_utils.h"
#include "internal/filesystem.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
// Generation of feature's getters/setters functions and kGetters, kSetters,
// kCpuInfoFlags and kHardwareCapabilities global tables.
#define DEFINE_TABLE_FEATURES \
FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \
PPC_FEATURE_UNIFIED_CACHE, 0) \
FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \
PPC_FEATURE_HAS_EFP_SINGLE, 0) \
FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \
PPC_FEATURE_HAS_EFP_DOUBLE, 0) \
FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \
0) \
FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
PPC_FEATURE2_HTM_NO_SUSPEND)
#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures
#include "define_tables.h"
static bool HandlePPCLine(const LineResult result,
PPCPlatformStrings* const strings) {
StringView line = result.line;
StringView key, value;
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
if (CpuFeatures_StringView_HasWord(key, "platform")) {
CpuFeatures_StringView_CopyString(value, strings->platform,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
CpuFeatures_StringView_CopyString(value, strings->model,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
CpuFeatures_StringView_CopyString(value, strings->machine,
sizeof(strings->platform));
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
CpuFeatures_StringView_CopyString(value, strings->cpu,
sizeof(strings->platform));
}
}
return !result.eof;
}
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
if (fd >= 0) {
StackLineReader reader;
StackLineReader_Initialize(&reader, fd);
for (;;) {
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
break;
}
}
CpuFeatures_CloseFile(fd);
}
}
static const PPCInfo kEmptyPPCInfo;
PPCInfo GetPPCInfo(void) {
/*
* On Power feature flags aren't currently in cpuinfo so we only look at
* the auxilary vector.
*/
PPCInfo info = kEmptyPPCInfo;
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
for (size_t i = 0; i < PPC_LAST_; ++i) {
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
kSetters[i](&info.features, true);
}
}
return info;
}
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
PPCPlatformStrings GetPPCPlatformStrings(void) {
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
FillProcCpuInfoData(&strings);
strings.type = CpuFeatures_GetPlatformType();
return strings;
}
////////////////////////////////////////////////////////////////////////////////
// Introspection functions
int GetPPCFeaturesEnumValue(const PPCFeatures* features,
PPCFeaturesEnum value) {
if (value >= PPC_LAST_) return false;
return kGetters[value](features);
}
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
if (value >= PPC_LAST_) return "unknown feature";
return kCpuInfoFlags[value];
}

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The following preprocessor constants must be defined before including this
// file:
// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features)
// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted.
// This file is to be included once per `cpuinfo_XXX.c` in order to construct
// feature getters and setters functions as well as several enum indexed tables
// from the db file.
// - `kGetters` a table of getters function pointers from feature enum to
// retrieve a feature,
// - `kSetters` a table of setters function pointers from feature enum to set a
// feature,
// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo
// flags,
// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by
// their feature enum.
#ifndef SRC_DEFINE_TABLES_H_
#define SRC_DEFINE_TABLES_H_
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES};
#undef FEATURE
#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
static const HardwareCapabilities kHardwareCapabilities[] = {
DEFINE_TABLE_FEATURES};
#undef FEATURE
#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) { \
features->NAME = value; \
} \
static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) { \
return features->NAME; \
}
DEFINE_TABLE_FEATURES
#undef FEATURE
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM,
static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*,
bool) = {DEFINE_TABLE_FEATURES};
#undef FEATURE
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM,
static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = {
DEFINE_TABLE_FEATURES};
#undef FEATURE
#endif // SRC_DEFINE_TABLES_H_

View File

@ -1,62 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/filesystem.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
// Implementation will be provided by test/filesystem_for_testing.cc.
#elif defined(_MSC_VER)
#include <io.h>
int CpuFeatures_OpenFile(const char* filename) {
int fd = -1;
_sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
return fd;
}
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
size_t buffer_size) {
return _read(file_descriptor, buffer, (unsigned int)buffer_size);
}
#else
#include <unistd.h>
int CpuFeatures_OpenFile(const char* filename) {
int result;
do {
result = open(filename, O_RDONLY);
} while (result == -1L && errno == EINTR);
return result;
}
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
size_t buffer_size) {
int result;
do {
result = read(file_descriptor, buffer, buffer_size);
} while (result == -1L && errno == EINTR);
return result;
}
#endif

View File

@ -1,182 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/hwcaps.h"
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#include "internal/filesystem.h"
#include "internal/string_view.h"
static bool IsSet(const uint32_t mask, const uint32_t value) {
if (mask == 0) return false;
return (value & mask) == mask;
}
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
const HardwareCapabilities hwcaps) {
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
}
#ifdef CPU_FEATURES_TEST
// In test mode, hwcaps_for_testing will define the following functions.
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
PlatformType CpuFeatures_GetPlatformType(void);
#else
// Debug facilities
#if defined(NDEBUG)
#define D(...)
#else
#include <stdio.h>
#define D(...) \
do { \
printf(__VA_ARGS__); \
fflush(stdout); \
} while (0)
#endif
////////////////////////////////////////////////////////////////////////////////
// Implementation of GetElfHwcapFromGetauxval
////////////////////////////////////////////////////////////////////////////////
#define AT_HWCAP 16
#define AT_HWCAP2 26
#define AT_PLATFORM 15
#define AT_BASE_PLATFORM 24
#if defined(HAVE_STRONG_GETAUXVAL)
#include <sys/auxv.h>
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
return getauxval(hwcap_type);
}
#elif defined(HAVE_DLFCN_H)
// On Android we probe the system's C library for a 'getauxval' function and
// call it if it exits, or return 0 for failure. This function is available
// since API level 20.
//
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
// case where some NDK developers use headers for a platform that is newer than
// the one really targetted by their application. This is typically done to use
// newer native APIs only when running on more recent Android versions, and
// requires careful symbol management.
//
// Note that getauxval() can't really be re-implemented here, because its
// implementation does not parse /proc/self/auxv. Instead it depends on values
// that are passed by the kernel at process-init time to the C runtime
// initialization layer.
#include <dlfcn.h>
typedef unsigned long getauxval_func_t(unsigned long);
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
uint32_t ret = 0;
void *libc_handle = NULL;
getauxval_func_t *func = NULL;
dlerror(); // Cleaning error state before calling dlopen.
libc_handle = dlopen("libc.so", RTLD_NOW);
if (!libc_handle) {
D("Could not dlopen() C library: %s\n", dlerror());
return 0;
}
func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
if (!func) {
D("Could not find getauxval() in C library\n");
} else {
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
ret = (uint32_t)(*func)(hwcap_type);
}
dlclose(libc_handle);
return ret;
}
#else
#error "This platform does not provide hardware capabilities."
#endif
// Implementation of GetHardwareCapabilities for OS that provide
// GetElfHwcapFromGetauxval().
// Fallback when getauxval is not available, retrieves hwcaps from
// "/proc/self/auxv".
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
struct {
uint32_t tag;
uint32_t value;
} entry;
uint32_t result = 0;
const char filepath[] = "/proc/self/auxv";
const int fd = CpuFeatures_OpenFile(filepath);
if (fd < 0) {
D("Could not open %s\n", filepath);
return 0;
}
for (;;) {
const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
if (ret < 0) {
D("Error while reading %s\n", filepath);
break;
}
// Detect end of list.
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
break;
}
if (entry.tag == hwcap_type) {
result = entry.value;
break;
}
}
CpuFeatures_CloseFile(fd);
return result;
}
// Retrieves hardware capabilities by first trying to call getauxval, if not
// available falls back to reading "/proc/self/auxv".
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
if (!hwcaps) {
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
}
return hwcaps;
}
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
HardwareCapabilities capabilities;
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
return capabilities;
}
PlatformType kEmptyPlatformType;
PlatformType CpuFeatures_GetPlatformType(void) {
PlatformType type = kEmptyPlatformType;
char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
if (platform != NULL)
CpuFeatures_StringView_CopyString(str(platform), type.platform,
sizeof(type.platform));
if (base_platform != NULL)
CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
sizeof(type.base_platform));
return type;
}
#endif // CPU_FEATURES_TEST

View File

@ -1,132 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/stack_line_reader.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include "internal/filesystem.h"
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
reader->view.ptr = reader->buffer;
reader->view.size = 0;
reader->skip_mode = false;
reader->fd = fd;
}
// Replaces the content of buffer with bytes from the file.
static int LoadFullBuffer(StackLineReader* reader) {
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
STACK_LINE_READER_BUFFER_SIZE);
assert(read >= 0);
reader->view.ptr = reader->buffer;
reader->view.size = read;
return read;
}
// Appends with bytes from the file to buffer, filling the remaining space.
static int LoadMore(StackLineReader* reader) {
char* const ptr = reader->buffer + reader->view.size;
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
assert(read >= 0);
assert(read <= (int)size_to_read);
reader->view.size += read;
return read;
}
static int IndexOfEol(StackLineReader* reader) {
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
}
// Relocate buffer's pending bytes at the beginning of the array and fills the
// remaining space with bytes from the file.
static int BringToFrontAndLoadMore(StackLineReader* reader) {
if (reader->view.size && reader->view.ptr != reader->buffer) {
memmove(reader->buffer, reader->view.ptr, reader->view.size);
}
reader->view.ptr = reader->buffer;
return LoadMore(reader);
}
// Loads chunks of buffer size from disks until it contains a newline character
// or end of file.
static void SkipToNextLine(StackLineReader* reader) {
for (;;) {
const int read = LoadFullBuffer(reader);
if (read == 0) {
break;
} else {
const int eol_index = IndexOfEol(reader);
if (eol_index >= 0) {
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
break;
}
}
}
}
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
LineResult result;
result.eof = eof;
result.full_line = full_line;
result.line = view;
return result;
}
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
static LineResult CreateEOFLineResult(StringView view) {
return CreateLineResult(true, true, view);
}
static LineResult CreateTruncatedLineResult(StringView view) {
return CreateLineResult(false, false, view);
}
static LineResult CreateValidLineResult(StringView view) {
return CreateLineResult(false, true, view);
}
LineResult StackLineReader_NextLine(StackLineReader* reader) {
if (reader->skip_mode) {
SkipToNextLine(reader);
reader->skip_mode = false;
}
{
const bool can_load_more =
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
int eol_index = IndexOfEol(reader);
if (eol_index < 0 && can_load_more) {
const int read = BringToFrontAndLoadMore(reader);
if (read == 0) {
return CreateEOFLineResult(reader->view);
}
eol_index = IndexOfEol(reader);
}
if (eol_index < 0) {
reader->skip_mode = true;
return CreateTruncatedLineResult(reader->view);
}
{
StringView line =
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
return CreateValidLineResult(line);
}
}
}

View File

@ -1,182 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/string_view.h"
#include <assert.h>
#include <ctype.h>
#include <string.h>
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
if (view.ptr && view.size) {
const char* const found = (const char*)memchr(view.ptr, c, view.size);
if (found) {
return (int)(found - view.ptr);
}
}
return -1;
}
int CpuFeatures_StringView_IndexOf(const StringView view,
const StringView sub_view) {
if (sub_view.size) {
StringView remainder = view;
while (remainder.size >= sub_view.size) {
const int found_index =
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
if (found_index < 0) break;
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
return (int)(remainder.ptr - view.ptr);
}
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
}
}
return -1;
}
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
if (a.size == b.size) {
return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
}
return false;
}
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
return a.ptr && b.ptr && b.size && a.size >= b.size
? memcmp(a.ptr, b.ptr, b.size) == 0
: false;
}
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr + count, str_view.size - count);
}
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
size_t count) {
if (count > str_view.size) {
return kEmptyStringView;
}
return view(str_view.ptr, str_view.size - count);
}
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
size_t count) {
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
}
char CpuFeatures_StringView_Front(const StringView view) {
assert(view.size);
assert(view.ptr);
return view.ptr[0];
}
char CpuFeatures_StringView_Back(const StringView view) {
assert(view.size);
return view.ptr[view.size - 1];
}
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
view = CpuFeatures_StringView_PopFront(view, 1);
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
view = CpuFeatures_StringView_PopBack(view, 1);
return view;
}
static int HexValue(const char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
// Returns -1 if view contains non digits.
static int ParsePositiveNumberWithBase(const StringView view, int base) {
int result = 0;
StringView remainder = view;
for (; remainder.size;
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
if (value < 0 || value >= base) return -1;
result = (result * base) + value;
}
return result;
}
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
if (view.size) {
const StringView hex_prefix = str("0x");
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
const StringView span_no_prefix =
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
return ParsePositiveNumberWithBase(span_no_prefix, 16);
}
return ParsePositiveNumberWithBase(view, 10);
}
return -1;
}
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
size_t dst_size) {
if (dst_size > 0) {
const size_t max_copy_size = dst_size - 1;
const size_t copy_size =
src.size > max_copy_size ? max_copy_size : src.size;
memcpy(dst, src.ptr, copy_size);
dst[copy_size] = '\0';
}
}
bool CpuFeatures_StringView_HasWord(const StringView line,
const char* const word_str) {
const StringView word = str(word_str);
StringView remainder = line;
for (;;) {
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
if (index_of_word < 0) {
return false;
} else {
const StringView before =
CpuFeatures_StringView_KeepFront(line, index_of_word);
const StringView after =
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
const bool valid_before =
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
const bool valid_after =
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
if (valid_before && valid_after) return true;
remainder =
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
}
}
return false;
}
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
StringView* key,
StringView* value) {
const StringView sep = str(": ");
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
if (index_of_separator < 0) return false;
*value = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
*key = CpuFeatures_StringView_TrimWhitespace(
CpuFeatures_StringView_KeepFront(line, index_of_separator));
return true;
}

View File

@ -1,438 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This program dumps current host data to the standard output.
// Output can be text or json if the `--json` flag is passed.
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#if defined(CPU_FEATURES_ARCH_X86)
#include "cpuinfo_x86.h"
#elif defined(CPU_FEATURES_ARCH_ARM)
#include "cpuinfo_arm.h"
#elif defined(CPU_FEATURES_ARCH_AARCH64)
#include "cpuinfo_aarch64.h"
#elif defined(CPU_FEATURES_ARCH_MIPS)
#include "cpuinfo_mips.h"
#elif defined(CPU_FEATURES_ARCH_PPC)
#include "cpuinfo_ppc.h"
#endif
// Design principles
// -----------------
// We build a tree structure containing all the data to be displayed.
// Then depending on the output type (text or json) we walk the tree and display
// the data accordingly.
// We use a bump allocator to allocate strings and nodes of the tree,
// Memory is not intended to be reclaimed.
typedef struct {
char* ptr;
size_t size;
} BumpAllocator;
char gGlobalBuffer[64 * 1024];
BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
.size = sizeof(gGlobalBuffer)};
static void internal_error() {
fputs("internal error\n", stderr);
exit(EXIT_FAILURE);
}
#define ALIGN 8
static void assertAligned() {
if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
}
static void BA_Align() {
while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
--gBumpAllocator.size;
++gBumpAllocator.ptr;
}
assertAligned();
}
// Update the available memory left in the BumpAllocator.
static void* BA_Bump(size_t size) {
assertAligned();
// Align size to next 8B boundary.
size = (size + ALIGN - 1) / ALIGN * ALIGN;
if (gBumpAllocator.size < size) internal_error();
void* ptr = gBumpAllocator.ptr;
gBumpAllocator.size -= size;
gBumpAllocator.ptr += size;
return ptr;
}
// The type of the nodes in the tree.
typedef enum {
NT_INVALID,
NT_INT,
NT_MAP,
NT_MAP_ENTRY,
NT_ARRAY,
NT_ARRAY_ELEMENT,
NT_STRING,
} NodeType;
// The node in the tree.
typedef struct Node {
NodeType type;
unsigned integer;
const char* string;
struct Node* value;
struct Node* next;
} Node;
// Creates an initialized Node.
static Node* BA_CreateNode(NodeType type) {
Node* tv = (Node*)BA_Bump(sizeof(Node));
assert(tv);
*tv = (Node){.type = type};
return tv;
}
// Adds an integer node.
static Node* CreateInt(int value) {
Node* tv = BA_CreateNode(NT_INT);
tv->integer = value;
return tv;
}
// Adds a string node.
// `value` must outlive the tree.
static Node* CreateConstantString(const char* value) {
Node* tv = BA_CreateNode(NT_STRING);
tv->string = value;
return tv;
}
// Adds a map node.
static Node* CreateMap() { return BA_CreateNode(NT_MAP); }
// Adds an array node.
static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); }
// Adds a formatted string node.
static Node* CreatePrintfString(const char* format, ...) {
va_list arglist;
va_start(arglist, format);
char* const ptr = gBumpAllocator.ptr;
const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
va_end(arglist);
if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
return CreateConstantString((char*)BA_Bump(written));
}
// Adds a string node.
static Node* CreateString(const char* value) {
return CreatePrintfString("%s", value);
}
// Adds a map entry node.
static void AddMapEntry(Node* map, const char* key, Node* value) {
assert(map && map->type == NT_MAP);
Node* current = map;
while (current->next) current = current->next;
current->next = (Node*)BA_Bump(sizeof(Node));
*current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
}
// Adds an array element node.
static void AddArrayElement(Node* array, Node* value) {
assert(array && array->type == NT_ARRAY);
Node* current = array;
while (current->next) current = current->next;
current->next = (Node*)BA_Bump(sizeof(Node));
*current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
}
static int cmp(const void* p1, const void* p2) {
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
}
#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
static void AddFlags(Node* map, const FeatureType* features) { \
size_t i; \
const char* ptrs[LastEnum] = {0}; \
size_t count = 0; \
for (i = 0; i < LastEnum; ++i) { \
if (HasFeature(features, i)) { \
ptrs[count] = FeatureName(i); \
++count; \
} \
} \
qsort((void*)ptrs, count, sizeof(char*), cmp); \
Node* const array = CreateArray(); \
for (i = 0; i < count; ++i) \
AddArrayElement(array, CreateConstantString(ptrs[i])); \
AddMapEntry(map, "flags", array); \
}
#if defined(CPU_FEATURES_ARCH_X86)
DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
X86_LAST_)
#elif defined(CPU_FEATURES_ARCH_ARM)
DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
ARM_LAST_)
#elif defined(CPU_FEATURES_ARCH_AARCH64)
DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
Aarch64Features, AARCH64_LAST_)
#elif defined(CPU_FEATURES_ARCH_MIPS)
DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
MipsFeatures, MIPS_LAST_)
#elif defined(CPU_FEATURES_ARCH_PPC)
DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
PPC_LAST_)
#endif
// Prints a json string with characters escaping.
static void printJsonString(const char* str) {
putchar('"');
for (; str && *str; ++str) {
switch (*str) {
case '\"':
case '\\':
case '/':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
putchar('\\');
}
putchar(*str);
}
putchar('"');
}
// Walks a Node and print it as json.
static void printJson(const Node* current) {
assert(current);
switch (current->type) {
case NT_INVALID:
break;
case NT_INT:
printf("%d", current->integer);
break;
case NT_STRING:
printJsonString(current->string);
break;
case NT_ARRAY:
putchar('[');
if (current->next) printJson(current->next);
putchar(']');
break;
case NT_MAP:
putchar('{');
if (current->next) printJson(current->next);
putchar('}');
break;
case NT_MAP_ENTRY:
printf("\"%s\":", current->string);
printJson(current->value);
if (current->next) {
putchar(',');
printJson(current->next);
}
break;
case NT_ARRAY_ELEMENT:
printJson(current->value);
if (current->next) {
putchar(',');
printJson(current->next);
}
break;
}
}
// Walks a Node and print it as text.
static void printTextField(const Node* current) {
switch (current->type) {
case NT_INVALID:
break;
case NT_INT:
printf("%3d (0x%02X)", current->integer, current->integer);
break;
case NT_STRING:
fputs(current->string, stdout);
break;
case NT_ARRAY:
if (current->next) printTextField(current->next);
break;
case NT_MAP:
if (current->next) {
printf("{");
printJson(current->next);
printf("}");
}
break;
case NT_MAP_ENTRY:
printf("%-15s : ", current->string);
printTextField(current->value);
if (current->next) {
putchar('\n');
printTextField(current->next);
}
break;
case NT_ARRAY_ELEMENT:
printTextField(current->value);
if (current->next) {
putchar(',');
printTextField(current->next);
}
break;
}
}
static void printTextRoot(const Node* current) {
if (current->type == NT_MAP && current->next) printTextField(current->next);
}
static void showUsage(const char* name) {
printf(
"\n"
"Usage: %s [options]\n"
" Options:\n"
" -h | --help Show help message.\n"
" -j | --json Format output as json instead of plain text.\n"
"\n",
name);
}
static Node* GetCacheTypeString(CacheType cache_type) {
switch (cache_type) {
case CPU_FEATURE_CACHE_NULL:
return CreateConstantString("null");
case CPU_FEATURE_CACHE_DATA:
return CreateConstantString("data");
case CPU_FEATURE_CACHE_INSTRUCTION:
return CreateConstantString("instruction");
case CPU_FEATURE_CACHE_UNIFIED:
return CreateConstantString("unified");
case CPU_FEATURE_CACHE_TLB:
return CreateConstantString("tlb");
case CPU_FEATURE_CACHE_DTLB:
return CreateConstantString("dtlb");
case CPU_FEATURE_CACHE_STLB:
return CreateConstantString("stlb");
case CPU_FEATURE_CACHE_PREFETCH:
return CreateConstantString("prefetch");
}
}
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
Node* array = CreateArray();
for (int i = 0; i < cache_info->size; ++i) {
CacheLevelInfo info = cache_info->levels[i];
Node* map = CreateMap();
AddMapEntry(map, "level", CreateInt(info.level));
AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
AddMapEntry(map, "ways", CreateInt(info.ways));
AddMapEntry(map, "line_size", CreateInt(info.line_size));
AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
AddArrayElement(array, map);
}
AddMapEntry(root, "cache_info", array);
}
static Node* CreateTree() {
Node* root = CreateMap();
#if defined(CPU_FEATURES_ARCH_X86)
char brand_string[49];
const X86Info info = GetX86Info();
const CacheInfo cache_info = GetX86CacheInfo();
FillX86BrandString(brand_string);
AddMapEntry(root, "arch", CreateString("x86"));
AddMapEntry(root, "brand", CreateString(brand_string));
AddMapEntry(root, "family", CreateInt(info.family));
AddMapEntry(root, "model", CreateInt(info.model));
AddMapEntry(root, "stepping", CreateInt(info.stepping));
AddMapEntry(root, "uarch",
CreateString(
GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
AddFlags(root, &info.features);
AddCacheInfo(root, &cache_info);
#elif defined(CPU_FEATURES_ARCH_ARM)
const ArmInfo info = GetArmInfo();
AddMapEntry(root, "arch", CreateString("ARM"));
AddMapEntry(root, "implementer", CreateInt(info.implementer));
AddMapEntry(root, "architecture", CreateInt(info.architecture));
AddMapEntry(root, "variant", CreateInt(info.variant));
AddMapEntry(root, "part", CreateInt(info.part));
AddMapEntry(root, "revision", CreateInt(info.revision));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_AARCH64)
const Aarch64Info info = GetAarch64Info();
AddMapEntry(root, "arch", CreateString("aarch64"));
AddMapEntry(root, "implementer", CreateInt(info.implementer));
AddMapEntry(root, "variant", CreateInt(info.variant));
AddMapEntry(root, "part", CreateInt(info.part));
AddMapEntry(root, "revision", CreateInt(info.revision));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_MIPS)
const MipsInfo info = GetMipsInfo();
AddMapEntry(root, "arch", CreateString("mips"));
AddFlags(root, &info.features);
#elif defined(CPU_FEATURES_ARCH_PPC)
const PPCInfo info = GetPPCInfo();
const PPCPlatformStrings strings = GetPPCPlatformStrings();
AddMapEntry(root, "arch", CreateString("ppc"));
AddMapEntry(root, "platform", CreateString(strings.platform));
AddMapEntry(root, "model", CreateString(strings.model));
AddMapEntry(root, "machine", CreateString(strings.machine));
AddMapEntry(root, "cpu", CreateString(strings.cpu));
AddMapEntry(root, "instruction", CreateString(strings.type.platform));
AddMapEntry(root, "microarchitecture",
CreateString(strings.type.base_platform));
AddFlags(root, &info.features);
#endif
return root;
}
int main(int argc, char** argv) {
BA_Align();
const Node* const root = CreateTree();
bool outputJson = false;
int i = 1;
for (; i < argc; ++i) {
const char* arg = argv[i];
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
outputJson = true;
} else {
showUsage(argv[0]);
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
}
if (outputJson)
printJson(root);
else
printTextRoot(root);
putchar('\n');
return EXIT_SUCCESS;
}

View File

@ -1,85 +0,0 @@
#
# libraries for tests
#
include_directories(../include)
add_definitions(-DCPU_FEATURES_TEST)
##------------------------------------------------------------------------------
add_library(string_view ../src/string_view.c)
##------------------------------------------------------------------------------
add_library(filesystem_for_testing filesystem_for_testing.cc)
target_compile_definitions(filesystem_for_testing PUBLIC CPU_FEATURES_MOCK_FILESYSTEM)
##------------------------------------------------------------------------------
add_library(hwcaps_for_testing hwcaps_for_testing.cc)
target_link_libraries(hwcaps_for_testing filesystem_for_testing)
##------------------------------------------------------------------------------
add_library(stack_line_reader ../src/stack_line_reader.c)
target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024)
target_link_libraries(stack_line_reader string_view)
##------------------------------------------------------------------------------
add_library(stack_line_reader_for_test ../src/stack_line_reader.c)
target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16)
target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing)
##------------------------------------------------------------------------------
add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c)
target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view)
#
# tests
#
link_libraries(gtest gmock_main)
## bit_utils_test
add_executable(bit_utils_test bit_utils_test.cc)
target_link_libraries(bit_utils_test)
add_test(NAME bit_utils_test COMMAND bit_utils_test)
##------------------------------------------------------------------------------
## string_view_test
add_executable(string_view_test string_view_test.cc ../src/string_view.c)
target_link_libraries(string_view_test string_view)
add_test(NAME string_view_test COMMAND string_view_test)
##------------------------------------------------------------------------------
## stack_line_reader_test
add_executable(stack_line_reader_test stack_line_reader_test.cc)
target_link_libraries(stack_line_reader_test stack_line_reader_for_test)
add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
##------------------------------------------------------------------------------
## cpuinfo_x86_test
if(PROCESSOR_IS_X86)
add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86)
if(APPLE)
target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME)
endif()
target_link_libraries(cpuinfo_x86_test all_libraries)
add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_arm_test
if(PROCESSOR_IS_ARM)
add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c)
target_link_libraries(cpuinfo_arm_test all_libraries)
add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_aarch64_test
if(PROCESSOR_IS_AARCH64)
add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c)
target_link_libraries(cpuinfo_aarch64_test all_libraries)
add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_mips_test
if(PROCESSOR_IS_MIPS)
add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c)
target_link_libraries(cpuinfo_mips_test all_libraries)
add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test)
endif()
##------------------------------------------------------------------------------
## cpuinfo_ppc_test
if(PROCESSOR_IS_POWER)
add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/cpuinfo_ppc.c)
target_link_libraries(cpuinfo_ppc_test all_libraries)
add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test)
endif()

View File

@ -1,53 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/bit_utils.h"
#include "gtest/gtest.h"
namespace cpu_features {
namespace {
TEST(UtilsTest, IsBitSet) {
for (size_t bit_set = 0; bit_set < 32; ++bit_set) {
const uint32_t value = 1UL << bit_set;
for (uint32_t i = 0; i < 32; ++i) {
EXPECT_EQ(IsBitSet(value, i), i == bit_set);
}
}
// testing 0, all bits should be 0.
for (uint32_t i = 0; i < 32; ++i) {
EXPECT_FALSE(IsBitSet(0, i));
}
// testing ~0, all bits should be 1.
for (uint32_t i = 0; i < 32; ++i) {
EXPECT_TRUE(IsBitSet(-1, i));
}
}
TEST(UtilsTest, ExtractBitRange) {
// Extracting all bits gives the same number.
EXPECT_EQ(ExtractBitRange(123, 31, 0), 123);
// Extracting 1 bit gives parity.
EXPECT_EQ(ExtractBitRange(123, 0, 0), 1);
EXPECT_EQ(ExtractBitRange(122, 0, 0), 0);
EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF);
EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42);
}
} // namespace
} // namespace cpu_features

View File

@ -1,171 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_aarch64.h"
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "hwcaps_for_testing.h"
namespace cpu_features {
namespace {
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
TEST(CpuinfoAarch64Test, FromHardwareCap) {
SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetAarch64Info();
EXPECT_TRUE(info.features.fp);
EXPECT_FALSE(info.features.asimd);
EXPECT_FALSE(info.features.evtstrm);
EXPECT_TRUE(info.features.aes);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
EXPECT_FALSE(info.features.crc32);
EXPECT_FALSE(info.features.atomics);
EXPECT_FALSE(info.features.fphp);
EXPECT_FALSE(info.features.asimdhp);
EXPECT_FALSE(info.features.cpuid);
EXPECT_FALSE(info.features.asimdrdm);
EXPECT_FALSE(info.features.jscvt);
EXPECT_FALSE(info.features.fcma);
EXPECT_FALSE(info.features.lrcpc);
EXPECT_FALSE(info.features.dcpop);
EXPECT_FALSE(info.features.sha3);
EXPECT_FALSE(info.features.sm3);
EXPECT_FALSE(info.features.sm4);
EXPECT_FALSE(info.features.asimddp);
EXPECT_FALSE(info.features.sha512);
EXPECT_FALSE(info.features.sve);
EXPECT_FALSE(info.features.asimdfhm);
EXPECT_FALSE(info.features.dit);
EXPECT_FALSE(info.features.uscat);
EXPECT_FALSE(info.features.ilrcpc);
EXPECT_FALSE(info.features.flagm);
EXPECT_FALSE(info.features.ssbs);
EXPECT_FALSE(info.features.sb);
EXPECT_FALSE(info.features.paca);
EXPECT_FALSE(info.features.pacg);
}
TEST(CpuinfoAarch64Test, FromHardwareCap2) {
SetHardwareCapabilities(AARCH64_HWCAP_FP,
AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetAarch64Info();
EXPECT_TRUE(info.features.fp);
EXPECT_TRUE(info.features.sve2);
EXPECT_TRUE(info.features.bti);
EXPECT_FALSE(info.features.dcpodp);
EXPECT_FALSE(info.features.sveaes);
EXPECT_FALSE(info.features.svepmull);
EXPECT_FALSE(info.features.svebitperm);
EXPECT_FALSE(info.features.svesha3);
EXPECT_FALSE(info.features.svesm4);
EXPECT_FALSE(info.features.flagm2);
EXPECT_FALSE(info.features.frint);
EXPECT_FALSE(info.features.svei8mm);
EXPECT_FALSE(info.features.svef32mm);
EXPECT_FALSE(info.features.svef64mm);
EXPECT_FALSE(info.features.svebf16);
EXPECT_FALSE(info.features.i8mm);
EXPECT_FALSE(info.features.bf16);
EXPECT_FALSE(info.features.dgh);
EXPECT_FALSE(info.features.rng);
}
TEST(CpuinfoAarch64Test, ARMCortexA53) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : AArch64 Processor rev 3 (aarch64)
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: AArch64
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 3)");
const auto info = GetAarch64Info();
EXPECT_EQ(info.implementer, 0x41);
EXPECT_EQ(info.variant, 0x0);
EXPECT_EQ(info.part, 0xd03);
EXPECT_EQ(info.revision, 3);
EXPECT_TRUE(info.features.fp);
EXPECT_TRUE(info.features.asimd);
EXPECT_TRUE(info.features.evtstrm);
EXPECT_TRUE(info.features.aes);
EXPECT_TRUE(info.features.pmull);
EXPECT_TRUE(info.features.sha1);
EXPECT_TRUE(info.features.sha2);
EXPECT_TRUE(info.features.crc32);
EXPECT_FALSE(info.features.atomics);
EXPECT_FALSE(info.features.fphp);
EXPECT_FALSE(info.features.asimdhp);
EXPECT_FALSE(info.features.cpuid);
EXPECT_FALSE(info.features.asimdrdm);
EXPECT_FALSE(info.features.jscvt);
EXPECT_FALSE(info.features.fcma);
EXPECT_FALSE(info.features.lrcpc);
EXPECT_FALSE(info.features.dcpop);
EXPECT_FALSE(info.features.sha3);
EXPECT_FALSE(info.features.sm3);
EXPECT_FALSE(info.features.sm4);
EXPECT_FALSE(info.features.asimddp);
EXPECT_FALSE(info.features.sha512);
EXPECT_FALSE(info.features.sve);
EXPECT_FALSE(info.features.asimdfhm);
EXPECT_FALSE(info.features.dit);
EXPECT_FALSE(info.features.uscat);
EXPECT_FALSE(info.features.ilrcpc);
EXPECT_FALSE(info.features.flagm);
EXPECT_FALSE(info.features.ssbs);
EXPECT_FALSE(info.features.sb);
EXPECT_FALSE(info.features.paca);
EXPECT_FALSE(info.features.pacg);
EXPECT_FALSE(info.features.dcpodp);
EXPECT_FALSE(info.features.sve2);
EXPECT_FALSE(info.features.sveaes);
EXPECT_FALSE(info.features.svepmull);
EXPECT_FALSE(info.features.svebitperm);
EXPECT_FALSE(info.features.svesha3);
EXPECT_FALSE(info.features.svesm4);
EXPECT_FALSE(info.features.flagm2);
EXPECT_FALSE(info.features.frint);
EXPECT_FALSE(info.features.svei8mm);
EXPECT_FALSE(info.features.svef32mm);
EXPECT_FALSE(info.features.svef64mm);
EXPECT_FALSE(info.features.svebf16);
EXPECT_FALSE(info.features.i8mm);
EXPECT_FALSE(info.features.bf16);
EXPECT_FALSE(info.features.dgh);
EXPECT_FALSE(info.features.rng);
EXPECT_FALSE(info.features.bti);
}
} // namespace
} // namespace cpu_features

View File

@ -1,354 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_arm.h"
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "hwcaps_for_testing.h"
namespace cpu_features {
namespace {
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
TEST(CpuinfoArmTest, FromHardwareCap) {
SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetArmInfo();
EXPECT_TRUE(info.features.vfp); // triggered by vfpv3
EXPECT_TRUE(info.features.vfpv3); // triggered by neon
EXPECT_TRUE(info.features.neon);
EXPECT_TRUE(info.features.aes);
EXPECT_TRUE(info.features.crc32);
EXPECT_FALSE(info.features.vfpv4);
EXPECT_FALSE(info.features.iwmmxt);
EXPECT_FALSE(info.features.crunch);
EXPECT_FALSE(info.features.thumbee);
EXPECT_FALSE(info.features.vfpv3d16);
EXPECT_FALSE(info.features.idiva);
EXPECT_FALSE(info.features.idivt);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
// check some random features with EnumValue():
EXPECT_TRUE(GetArmFeaturesEnumValue(&info.features, ARM_VFP));
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, ARM_VFPV4));
// out of bound EnumValue() check
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, (ArmFeaturesEnum)~0x0));
}
TEST(CpuinfoArmTest, ODroidFromCpuInfo) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv7 Processor rev 3 (v71)
BogoMIPS : 120.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x2
CPU part : 0xc0f
CPU revision : 3)");
const auto info = GetArmInfo();
EXPECT_EQ(info.implementer, 0x41);
EXPECT_EQ(info.variant, 0x2);
EXPECT_EQ(info.part, 0xc0f);
EXPECT_EQ(info.revision, 3);
EXPECT_EQ(info.architecture, 7);
EXPECT_FALSE(info.features.swp);
EXPECT_TRUE(info.features.half);
EXPECT_TRUE(info.features.thumb);
EXPECT_FALSE(info.features._26bit);
EXPECT_TRUE(info.features.fastmult);
EXPECT_FALSE(info.features.fpa);
EXPECT_TRUE(info.features.vfp);
EXPECT_TRUE(info.features.edsp);
EXPECT_FALSE(info.features.java);
EXPECT_FALSE(info.features.iwmmxt);
EXPECT_FALSE(info.features.crunch);
EXPECT_FALSE(info.features.thumbee);
EXPECT_TRUE(info.features.neon);
EXPECT_TRUE(info.features.vfpv3);
EXPECT_FALSE(info.features.vfpv3d16);
EXPECT_TRUE(info.features.tls);
EXPECT_TRUE(info.features.vfpv4);
EXPECT_TRUE(info.features.idiva);
EXPECT_TRUE(info.features.idivt);
EXPECT_TRUE(info.features.vfpd32);
EXPECT_TRUE(info.features.lpae);
EXPECT_FALSE(info.features.evtstrm);
EXPECT_FALSE(info.features.aes);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
EXPECT_FALSE(info.features.crc32);
}
// Linux test-case
TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS : 697.95
Features : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 7
Hardware : BCM2835
Revision : 9000c1
Serial : 000000006cd946f3)");
const auto info = GetArmInfo();
EXPECT_EQ(info.implementer, 0x41);
EXPECT_EQ(info.variant, 0x0);
EXPECT_EQ(info.part, 0xb76);
EXPECT_EQ(info.revision, 7);
EXPECT_EQ(info.architecture, 6);
EXPECT_FALSE(info.features.swp);
EXPECT_TRUE(info.features.half);
EXPECT_TRUE(info.features.thumb);
EXPECT_FALSE(info.features._26bit);
EXPECT_TRUE(info.features.fastmult);
EXPECT_FALSE(info.features.fpa);
EXPECT_TRUE(info.features.vfp);
EXPECT_TRUE(info.features.edsp);
EXPECT_TRUE(info.features.java);
EXPECT_FALSE(info.features.iwmmxt);
EXPECT_FALSE(info.features.crunch);
EXPECT_FALSE(info.features.thumbee);
EXPECT_FALSE(info.features.neon);
EXPECT_FALSE(info.features.vfpv3);
EXPECT_FALSE(info.features.vfpv3d16);
EXPECT_TRUE(info.features.tls);
EXPECT_FALSE(info.features.vfpv4);
EXPECT_FALSE(info.features.idiva);
EXPECT_FALSE(info.features.idivt);
EXPECT_FALSE(info.features.vfpd32);
EXPECT_FALSE(info.features.lpae);
EXPECT_FALSE(info.features.evtstrm);
EXPECT_FALSE(info.features.aes);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
EXPECT_FALSE(info.features.crc32);
}
TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
model name : ARMv7 Processor rev 1 (v7l)
BogoMIPS : 50.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
processor : 1
model name : ARMv7 Processor rev 1 (v7l)
BogoMIPS : 50.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x4
CPU part : 0xc09
CPU revision : 1
Hardware : Marvell Armada 380/385 (Device Tree)
Revision : 0000
Serial : 0000000000000000)");
const auto info = GetArmInfo();
EXPECT_EQ(info.implementer, 0x41);
EXPECT_EQ(info.variant, 0x4);
EXPECT_EQ(info.part, 0xc09);
EXPECT_EQ(info.revision, 1);
EXPECT_EQ(info.architecture, 7);
EXPECT_FALSE(info.features.swp);
EXPECT_TRUE(info.features.half);
EXPECT_TRUE(info.features.thumb);
EXPECT_FALSE(info.features._26bit);
EXPECT_TRUE(info.features.fastmult);
EXPECT_FALSE(info.features.fpa);
EXPECT_TRUE(info.features.vfp);
EXPECT_TRUE(info.features.edsp);
EXPECT_FALSE(info.features.java);
EXPECT_FALSE(info.features.iwmmxt);
EXPECT_FALSE(info.features.crunch);
EXPECT_FALSE(info.features.thumbee);
EXPECT_TRUE(info.features.neon);
EXPECT_TRUE(info.features.vfpv3);
EXPECT_FALSE(info.features.vfpv3d16);
EXPECT_TRUE(info.features.tls);
EXPECT_FALSE(info.features.vfpv4);
EXPECT_FALSE(info.features.idiva);
EXPECT_FALSE(info.features.idivt);
EXPECT_TRUE(info.features.vfpd32);
EXPECT_FALSE(info.features.lpae);
EXPECT_FALSE(info.features.evtstrm);
EXPECT_FALSE(info.features.aes);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
EXPECT_FALSE(info.features.crc32);
}
// Android test-case
// http://code.google.com/p/android/issues/detail?id=10812
TEST(CpuinfoArmTest, InvalidArmv7) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : ARMv6-compatible processor rev 6 (v6l)
BogoMIPS : 199.47
Features : swp half thumb fastmult vfp edsp java
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 6
Hardware : SPICA
Revision : 0020
Serial : 33323613546d00ec )");
const auto info = GetArmInfo();
EXPECT_EQ(info.architecture, 6);
EXPECT_TRUE(info.features.swp);
EXPECT_TRUE(info.features.half);
EXPECT_TRUE(info.features.thumb);
EXPECT_FALSE(info.features._26bit);
EXPECT_TRUE(info.features.fastmult);
EXPECT_FALSE(info.features.fpa);
EXPECT_TRUE(info.features.vfp);
EXPECT_TRUE(info.features.edsp);
EXPECT_TRUE(info.features.java);
EXPECT_FALSE(info.features.iwmmxt);
EXPECT_FALSE(info.features.crunch);
EXPECT_FALSE(info.features.thumbee);
EXPECT_FALSE(info.features.neon);
EXPECT_FALSE(info.features.vfpv3);
EXPECT_FALSE(info.features.vfpv3d16);
EXPECT_FALSE(info.features.tls);
EXPECT_FALSE(info.features.vfpv4);
EXPECT_FALSE(info.features.idiva);
EXPECT_FALSE(info.features.idivt);
EXPECT_FALSE(info.features.vfpd32);
EXPECT_FALSE(info.features.lpae);
EXPECT_FALSE(info.features.evtstrm);
EXPECT_FALSE(info.features.aes);
EXPECT_FALSE(info.features.pmull);
EXPECT_FALSE(info.features.sha1);
EXPECT_FALSE(info.features.sha2);
EXPECT_FALSE(info.features.crc32);
}
// Android test-case
// https://crbug.com/341598.
TEST(CpuinfoArmTest, InvalidNeon) {
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor: ARMv7 Processory rev 0 (v71)
processor: 0
BogoMIPS: 13.50
Processor: 1
BogoMIPS: 13.50
Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
CPU implementer : 0x51
CPU architecture: 7
CPU variant: 0x1
CPU part: 0x04d
CPU revision: 0
Hardware: SAMSUNG M2
Revision: 0010
Serial: 00001e030000354e)");
const auto info = GetArmInfo();
EXPECT_TRUE(info.features.swp);
EXPECT_FALSE(info.features.neon);
}
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
// support.
TEST(CpuinfoArmTest, Nexus4_0x510006f2) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0x0
CPU part : 0x6f
CPU revision : 2)");
const auto info = GetArmInfo();
EXPECT_TRUE(info.features.idiva);
EXPECT_TRUE(info.features.idivt);
EXPECT_EQ(GetArmCpuId(&info), 0x510006f2);
}
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
// support.
TEST(CpuinfoArmTest, Nexus4_0x510006f3) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0x0
CPU part : 0x6f
CPU revision : 3)");
const auto info = GetArmInfo();
EXPECT_TRUE(info.features.idiva);
EXPECT_TRUE(info.features.idivt);
EXPECT_EQ(GetArmCpuId(&info), 0x510006f3);
}
// The emulator-specific Android 4.2 kernel fails to report support for the
// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual
// CPU implemented by the emulator.
TEST(CpuinfoArmTest, EmulatorSpecificIdiv) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(Processor : ARMv7 Processor rev 0 (v7l)
BogoMIPS : 629.14
Features : swp half thumb fastmult vfp edsp neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xc08
CPU revision : 0
Hardware : Goldfish
Revision : 0000
Serial : 0000000000000000)");
const auto info = GetArmInfo();
EXPECT_TRUE(info.features.idiva);
}
} // namespace
} // namespace cpu_features

View File

@ -1,126 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_mips.h"
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "hwcaps_for_testing.h"
#include "internal/stack_line_reader.h"
#include "internal/string_view.h"
namespace cpu_features {
namespace {
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetMipsInfo();
EXPECT_TRUE(info.features.msa);
EXPECT_FALSE(info.features.eva);
EXPECT_TRUE(info.features.r6);
}
TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
SetHardwareCapabilities(MIPS_HWCAP_MSA, 0);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetMipsInfo();
EXPECT_TRUE(info.features.msa);
EXPECT_FALSE(info.features.eva);
}
TEST(CpuinfoMipsTest, Ci40) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0)
machine : IMG Marduk Ci40 with cc2520
processor : 0
cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0
BogoMIPS : 363.72
wait instruction : yes
microsecond timers : yes
tlb_entries : 64
extra interrupt vector : yes
hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa : mips1 mips2 mips32r1 mips32r2
ASEs implemented : mips16 dsp mt eva
shadow register sets : 1
kscratch registers : 0
package : 0
core : 0
VCED exceptions : not available
VCEI exceptions : not available
VPE : 0
)");
const auto info = GetMipsInfo();
EXPECT_FALSE(info.features.msa);
EXPECT_TRUE(info.features.eva);
}
TEST(CpuinfoMipsTest, AR7161) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(system type : Atheros AR7161 rev 2
machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC
processor : 0
cpu model : MIPS 24Kc V7.4
BogoMIPS : 452.19
wait instruction : yes
microsecond timers : yes
tlb_entries : 16
extra interrupt vector : yes
hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8]
ASEs implemented : mips16
shadow register sets : 1
kscratch registers : 0
core : 0
VCED exceptions : not available
VCEI exceptions : not available
)");
const auto info = GetMipsInfo();
EXPECT_FALSE(info.features.msa);
EXPECT_FALSE(info.features.eva);
}
TEST(CpuinfoMipsTest, Goldfish) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish
Hardware : goldfish
Revison : 1
processor : 0
cpu model : MIPS 24Kc V0.0 FPU V0.0
BogoMIPS : 1042.02
wait instruction : yes
microsecond timers : yes
tlb_entries : 16
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
ASEs implemented :
shadow register sets : 1
core : 0
VCED exceptions : not available
VCEI exceptions : not available
)");
const auto info = GetMipsInfo();
EXPECT_FALSE(info.features.msa);
EXPECT_FALSE(info.features.eva);
}
} // namespace
} // namespace cpu_features

View File

@ -1,119 +0,0 @@
// Copyright 2018 IBM.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_ppc.h"
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "hwcaps_for_testing.h"
#include "internal/string_view.h"
namespace cpu_features {
namespace {
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
TEST(CpustringsPPCTest, FromHardwareCap) {
SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX,
PPC_FEATURE2_ARCH_3_00);
GetEmptyFilesystem(); // disabling /proc/cpuinfo
const auto info = GetPPCInfo();
EXPECT_TRUE(info.features.fpu);
EXPECT_FALSE(info.features.mmu);
EXPECT_TRUE(info.features.vsx);
EXPECT_TRUE(info.features.arch300);
EXPECT_FALSE(info.features.power4);
EXPECT_FALSE(info.features.altivec);
EXPECT_FALSE(info.features.vcrypto);
EXPECT_FALSE(info.features.htm);
}
TEST(CpustringsPPCTest, Blade) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 14
cpu : POWER7 (architected), altivec supported
clock : 3000.000000MHz
revision : 2.1 (pvr 003f 0201)
processor : 15
cpu : POWER7 (architected), altivec supported
clock : 3000.000000MHz
revision : 2.1 (pvr 003f 0201)
timebase : 512000000
platform : pSeries
model : IBM,8406-70Y
machine : CHRP IBM,8406-70Y)");
SetPlatformTypes("power7", "power8");
const auto strings = GetPPCPlatformStrings();
ASSERT_STREQ(strings.platform, "pSeries");
ASSERT_STREQ(strings.model, "IBM,8406-70Y");
ASSERT_STREQ(strings.machine, "CHRP IBM,8406-70Y");
ASSERT_STREQ(strings.cpu, "POWER7 (architected), altivec supported");
ASSERT_STREQ(strings.type.platform, "power7");
ASSERT_STREQ(strings.type.base_platform, "power8");
}
TEST(CpustringsPPCTest, Firestone) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 126
cpu : POWER8 (raw), altivec supported
clock : 2061.000000MHz
revision : 2.0 (pvr 004d 0200)
processor : 127
cpu : POWER8 (raw), altivec supported
clock : 2061.000000MHz
revision : 2.0 (pvr 004d 0200)
timebase : 512000000
platform : PowerNV
model : 8335-GTA
machine : PowerNV 8335-GTA
firmware : OPAL v3)");
const auto strings = GetPPCPlatformStrings();
ASSERT_STREQ(strings.platform, "PowerNV");
ASSERT_STREQ(strings.model, "8335-GTA");
ASSERT_STREQ(strings.machine, "PowerNV 8335-GTA");
ASSERT_STREQ(strings.cpu, "POWER8 (raw), altivec supported");
}
TEST(CpustringsPPCTest, w8) {
DisableHardwareCapabilities();
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo",
R"(processor : 143
cpu : POWER9, altivec supported
clock : 2300.000000MHz
revision : 2.2 (pvr 004e 1202)
timebase : 512000000
platform : PowerNV
model : 0000000000000000
machine : PowerNV 0000000000000000
firmware : OPAL
MMU : Radix)");
const auto strings = GetPPCPlatformStrings();
ASSERT_STREQ(strings.platform, "PowerNV");
ASSERT_STREQ(strings.model, "0000000000000000");
ASSERT_STREQ(strings.machine, "PowerNV 0000000000000000");
ASSERT_STREQ(strings.cpu, "POWER9, altivec supported");
}
} // namespace
} // namespace cpu_features

View File

@ -1,533 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cpuinfo_x86.h"
#include <cassert>
#include <cstdio>
#include <map>
#include <set>
#if defined(CPU_FEATURES_OS_WINDOWS)
#include <windows.h> // IsProcessorFeaturePresent
#endif // CPU_FEATURES_OS_WINDOWS
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
#include "internal/cpuid_x86.h"
namespace cpu_features {
class FakeCpu {
public:
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) const {
const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx));
if (itr != cpuid_leaves_.end()) {
return itr->second;
}
return {0, 0, 0, 0};
}
uint32_t GetXCR0Eax() const { return xcr0_eax_; }
void SetLeaves(std::map<std::pair<uint32_t, int>, Leaf> configuration) {
cpuid_leaves_ = std::move(configuration);
}
void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) {
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
}
#if defined(CPU_FEATURES_OS_DARWIN)
bool GetDarwinSysCtlByName(std::string name) const {
return darwin_sysctlbyname_.count(name);
}
void SetDarwinSysCtlByName(std::string name) {
darwin_sysctlbyname_.insert(name);
}
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
return windows_isprocessorfeaturepresent_.count(ProcessorFeature);
}
void SetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
windows_isprocessorfeaturepresent_.insert(ProcessorFeature);
}
#endif // CPU_FEATURES_OS_WINDOWS
private:
std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
#if defined(CPU_FEATURES_OS_DARWIN)
std::set<std::string> darwin_sysctlbyname_;
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
std::set<DWORD> windows_isprocessorfeaturepresent_;
#endif // CPU_FEATURES_OS_WINDOWS
uint32_t xcr0_eax_;
};
FakeCpu* g_fake_cpu = nullptr;
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
}
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
#if defined(CPU_FEATURES_OS_DARWIN)
extern "C" bool GetDarwinSysCtlByName(const char* name) {
return g_fake_cpu->GetDarwinSysCtlByName(name);
}
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_WINDOWS)
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
}
#endif // CPU_FEATURES_OS_WINDOWS
namespace {
class CpuidX86Test : public ::testing::Test {
protected:
void SetUp() override { g_fake_cpu = new FakeCpu(); }
void TearDown() override { delete g_fake_cpu; }
};
TEST_F(CpuidX86Test, SandyBridge) {
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x02A);
EXPECT_EQ(info.stepping, 0x06);
// Leaf 7 is zeroed out so none of the Leaf 7 flags are set.
const auto features = info.features;
EXPECT_FALSE(features.erms);
EXPECT_FALSE(features.avx2);
EXPECT_FALSE(features.avx512f);
EXPECT_FALSE(features.avx512cd);
EXPECT_FALSE(features.avx512er);
EXPECT_FALSE(features.avx512pf);
EXPECT_FALSE(features.avx512bw);
EXPECT_FALSE(features.avx512dq);
EXPECT_FALSE(features.avx512vl);
EXPECT_FALSE(features.avx512ifma);
EXPECT_FALSE(features.avx512vbmi);
EXPECT_FALSE(features.avx512vbmi2);
EXPECT_FALSE(features.avx512vnni);
EXPECT_FALSE(features.avx512bitalg);
EXPECT_FALSE(features.avx512vpopcntdq);
EXPECT_FALSE(features.avx512_4vnniw);
EXPECT_FALSE(features.avx512_4fmaps);
// All old cpu features should be set.
EXPECT_TRUE(features.aes);
EXPECT_TRUE(features.ssse3);
EXPECT_TRUE(features.sse4_1);
EXPECT_TRUE(features.sse4_2);
EXPECT_TRUE(features.avx);
EXPECT_FALSE(features.sha);
EXPECT_TRUE(features.popcnt);
EXPECT_FALSE(features.movbe);
EXPECT_FALSE(features.rdrnd);
}
const int KiB = 1024;
const int MiB = 1024 * KiB;
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) {
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
});
// avx is disabled if os does not support backing up ymm registers.
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
EXPECT_FALSE(GetX86Info().features.avx);
// avx is disabled if os does not support backing up ymm registers.
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
EXPECT_TRUE(GetX86Info().features.avx);
}
TEST_F(CpuidX86Test, SkyLake) {
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x04E);
EXPECT_EQ(info.stepping, 0x03);
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
}
TEST_F(CpuidX86Test, Branding) {
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
{{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
});
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
}
TEST_F(CpuidX86Test, KabyLakeCache) {
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}},
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
});
const auto info = GetX86CacheInfo();
EXPECT_EQ(info.size, 4);
EXPECT_EQ(info.levels[0].level, 1);
EXPECT_EQ(info.levels[0].cache_type, 1);
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
EXPECT_EQ(info.levels[0].ways, 8);
EXPECT_EQ(info.levels[0].line_size, 64);
EXPECT_EQ(info.levels[0].tlb_entries, 64);
EXPECT_EQ(info.levels[0].partitioning, 1);
EXPECT_EQ(info.levels[1].level, 1);
EXPECT_EQ(info.levels[1].cache_type, 2);
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
EXPECT_EQ(info.levels[1].ways, 8);
EXPECT_EQ(info.levels[1].line_size, 64);
EXPECT_EQ(info.levels[1].tlb_entries, 64);
EXPECT_EQ(info.levels[1].partitioning, 1);
EXPECT_EQ(info.levels[2].level, 2);
EXPECT_EQ(info.levels[2].cache_type, 3);
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
EXPECT_EQ(info.levels[2].ways, 4);
EXPECT_EQ(info.levels[2].line_size, 64);
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
EXPECT_EQ(info.levels[2].partitioning, 1);
EXPECT_EQ(info.levels[3].level, 3);
EXPECT_EQ(info.levels[3].cache_type, 3);
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
EXPECT_EQ(info.levels[3].ways, 12);
EXPECT_EQ(info.levels[3].line_size, 64);
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
EXPECT_EQ(info.levels[3].partitioning, 1);
}
TEST_F(CpuidX86Test, HSWCache) {
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}},
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
});
const auto info = GetX86CacheInfo();
EXPECT_EQ(info.size, 4);
EXPECT_EQ(info.levels[0].level, 1);
EXPECT_EQ(info.levels[0].cache_type, 1);
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
EXPECT_EQ(info.levels[0].ways, 8);
EXPECT_EQ(info.levels[0].line_size, 64);
EXPECT_EQ(info.levels[0].tlb_entries, 64);
EXPECT_EQ(info.levels[0].partitioning, 1);
EXPECT_EQ(info.levels[1].level, 1);
EXPECT_EQ(info.levels[1].cache_type, 2);
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
EXPECT_EQ(info.levels[1].ways, 8);
EXPECT_EQ(info.levels[1].line_size, 64);
EXPECT_EQ(info.levels[1].tlb_entries, 64);
EXPECT_EQ(info.levels[1].partitioning, 1);
EXPECT_EQ(info.levels[2].level, 2);
EXPECT_EQ(info.levels[2].cache_type, 3);
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
EXPECT_EQ(info.levels[2].ways, 8);
EXPECT_EQ(info.levels[2].line_size, 64);
EXPECT_EQ(info.levels[2].tlb_entries, 512);
EXPECT_EQ(info.levels[2].partitioning, 1);
EXPECT_EQ(info.levels[3].level, 3);
EXPECT_EQ(info.levels[3].cache_type, 3);
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
EXPECT_EQ(info.levels[3].ways, 12);
EXPECT_EQ(info.levels[3].line_size, 64);
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
EXPECT_EQ(info.levels[3].partitioning, 1);
}
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
TEST_F(CpuidX86Test, AMD_K15) {
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
{{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
{{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
{{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
{{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
{{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "AuthenticAMD");
EXPECT_EQ(info.family, 0x15);
EXPECT_EQ(info.model, 0x38);
EXPECT_EQ(info.stepping, 0x01);
EXPECT_EQ(GetX86Microarchitecture(&info),
X86Microarchitecture::AMD_BULLDOZER);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
TEST_F(CpuidX86Test, Nehalem) {
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor :
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004122, 0x00C0003F, 0x0000007F, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C03C163, 0x03C0003F, 0x00000FFF, 0x00000002}},
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00021120}},
{{0x00000006, 0}, Leaf{0x00000001, 0x00000002, 0x00000001, 0x00000000}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x0000000A, 0}, Leaf{0x07300403, 0x00000000, 0x00000000, 0x00000603}},
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
{{0x0000000B, 0}, Leaf{0x00000004, 0x00000002, 0x00000201, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x28100000}},
{{0x80000002, 0}, Leaf{0x756E6547, 0x20656E69, 0x65746E49, 0x2952286C}},
{{0x80000003, 0}, Leaf{0x55504320, 0x20202020, 0x20202020, 0x40202020}},
{{0x80000004, 0}, Leaf{0x30303020, 0x20402030, 0x37382E31, 0x007A4847}},
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x01006040, 0x00000000}},
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
{{0x80000008, 0}, Leaf{0x00003028, 0x00000000, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x1A);
EXPECT_EQ(info.stepping, 0x02);
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz");
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
TEST_F(CpuidX86Test, Atom) {
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000004, 0}, Leaf{0x1C000121, 0x0140003F, 0x0000003F, 0x00000001}},
{{0x00000004, 1}, Leaf{0x1C000122, 0x01C0003F, 0x0000003F, 0x00000001}},
{{0x00000004, 2}, Leaf{0x1C00C143, 0x03C0003F, 0x000003FF, 0x00000001}},
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x33000020}},
{{0x00000006, 0}, Leaf{0x00000005, 0x00000002, 0x00000009, 0x00000000}},
{{0x00000007, 0}, Leaf{0x00000000, 0x00002282, 0x00000000, 0x00000000}},
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x0000000A, 0}, Leaf{0x07280203, 0x00000000, 0x00000000, 0x00004503}},
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
{{0x0000000B, 1}, Leaf{0x00000004, 0x00000004, 0x00000201, 0x00000000}},
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000101, 0x28100000}},
{{0x80000002, 0}, Leaf{0x20202020, 0x6E492020, 0x286C6574, 0x43202952}},
{{0x80000003, 0}, Leaf{0x72656C65, 0x52286E6F, 0x50432029, 0x4A202055}},
{{0x80000004, 0}, Leaf{0x30303931, 0x20402020, 0x39392E31, 0x007A4847}},
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x04008040, 0x00000000}},
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
{{0x80000008, 0}, Leaf{0x00003024, 0x00000000, 0x00000000, 0x00000000}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x37);
EXPECT_EQ(info.stepping, 0x03);
EXPECT_EQ(GetX86Microarchitecture(&info),
X86Microarchitecture::INTEL_ATOM_SMT);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz");
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
TEST_F(CpuidX86Test, P3) {
// Pre AVX cpus don't have xsave
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
#endif // CPU_FEATURES_OS_WINDOWS
#if defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
#endif // CPU_FEATURES_OS_DARWIN
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse
)");
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x4CECC782, 0x00006778}},
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
EXPECT_EQ(info.family, 0x06);
EXPECT_EQ(info.model, 0x07);
EXPECT_EQ(info.stepping, 0x03);
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN);
char brand_string[49];
FillX86BrandString(brand_string);
EXPECT_STREQ(brand_string, "");
EXPECT_TRUE(info.features.mmx);
EXPECT_TRUE(info.features.sse);
EXPECT_FALSE(info.features.sse2);
EXPECT_FALSE(info.features.sse3);
#ifndef CPU_FEATURES_OS_WINDOWS
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_FALSE(info.features.ssse3);
EXPECT_FALSE(info.features.sse4_1);
EXPECT_FALSE(info.features.sse4_2);
#endif // CPU_FEATURES_OS_WINDOWS
}
// TODO(user): test what happens when xsave/osxsave are not present.
// TODO(user): test what happens when xmm/ymm/zmm os support are not
// present.
} // namespace
} // namespace cpu_features

View File

@ -1,103 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "filesystem_for_testing.h"
#include <cassert>
#include <climits>
#include <cstdio>
#include <cstring>
#include <utility>
namespace cpu_features {
FakeFile::FakeFile(int file_descriptor, const char* content)
: file_descriptor_(file_descriptor), content_(content) {}
FakeFile::~FakeFile() { assert(!opened_); }
void FakeFile::Open() {
assert(!opened_);
opened_ = true;
}
void FakeFile::Close() {
assert(opened_);
opened_ = false;
}
int FakeFile::Read(int fd, void* buf, size_t count) {
assert(count < INT_MAX);
assert(fd == file_descriptor_);
const size_t remainder = content_.size() - head_index_;
const size_t read = count > remainder ? remainder : count;
memcpy(buf, content_.data() + head_index_, read);
head_index_ += read;
assert(read < INT_MAX);
return (int)read;
}
void FakeFilesystem::Reset() { files_.clear(); }
FakeFile* FakeFilesystem::CreateFile(const std::string& filename,
const char* content) {
auto& file = files_[filename];
file =
std::unique_ptr<FakeFile>(new FakeFile(next_file_descriptor_++, content));
return file.get();
}
FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const {
const auto itr = files_.find(filename);
return itr == files_.end() ? nullptr : itr->second.get();
}
FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const {
for (const auto& filename_file_pair : files_) {
FakeFile* const file_ptr = filename_file_pair.second.get();
if (file_ptr->GetFileDescriptor() == file_descriptor) {
return file_ptr;
}
}
assert(false);
return nullptr;
}
static FakeFilesystem* kFilesystem = new FakeFilesystem();
FakeFilesystem& GetEmptyFilesystem() {
kFilesystem->Reset();
return *kFilesystem;
}
extern "C" int CpuFeatures_OpenFile(const char* filename) {
auto* const file = kFilesystem->FindFileOrNull(filename);
if (file) {
file->Open();
return file->GetFileDescriptor();
}
return -1;
}
extern "C" void CpuFeatures_CloseFile(int file_descriptor) {
kFilesystem->FindFileOrDie(file_descriptor)->Close();
}
extern "C" int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
size_t buffer_size) {
return kFilesystem->FindFileOrDie(file_descriptor)
->Read(file_descriptor, buffer, buffer_size);
}
} // namespace cpu_features

View File

@ -1,61 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Implements a fake filesystem, useful for tests.
#ifndef CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
#define CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
#include <memory>
#include <string>
#include <unordered_map>
#include "internal/filesystem.h"
namespace cpu_features {
class FakeFile {
public:
explicit FakeFile(int file_descriptor, const char* content);
~FakeFile();
void Open();
void Close();
int Read(int fd, void* buf, size_t count);
int GetFileDescriptor() const { return file_descriptor_; }
private:
const int file_descriptor_;
const std::string content_;
bool opened_ = false;
size_t head_index_ = 0;
};
class FakeFilesystem {
public:
void Reset();
FakeFile* CreateFile(const std::string& filename, const char* content);
FakeFile* FindFileOrDie(const int file_descriptor) const;
FakeFile* FindFileOrNull(const std::string& filename) const;
private:
int next_file_descriptor_ = 0;
std::unordered_map<std::string, std::unique_ptr<FakeFile>> files_;
};
FakeFilesystem& GetEmptyFilesystem();
} // namespace cpu_features
#endif // CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_

View File

@ -1,46 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "hwcaps_for_testing.h"
#include <string.h>
#include "internal/string_view.h"
namespace cpu_features {
namespace {
static auto* const g_hardware_capabilities = new HardwareCapabilities();
static auto* const g_platform_types = new PlatformType();
} // namespace
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) {
g_hardware_capabilities->hwcaps = hwcaps;
g_hardware_capabilities->hwcaps2 = hwcaps2;
}
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
return *g_hardware_capabilities;
}
void SetPlatformTypes(const char* platform, const char* base_platform) {
CpuFeatures_StringView_CopyString(str(platform), g_platform_types->platform,
sizeof(g_platform_types->platform));
CpuFeatures_StringView_CopyString(str(base_platform),
g_platform_types->base_platform,
sizeof(g_platform_types->base_platform));
}
PlatformType CpuFeatures_GetPlatformType(void) { return *g_platform_types; }
} // namespace cpu_features

View File

@ -1,27 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
#define CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
#include "internal/hwcaps.h"
namespace cpu_features {
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2);
void SetPlatformTypes(const char *platform, const char *base_platform);
} // namespace cpu_features
#endif // CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_

View File

@ -1,132 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/stack_line_reader.h"
#include "filesystem_for_testing.h"
#include "gtest/gtest.h"
namespace cpu_features {
bool operator==(const StringView& a, const StringView& b) {
return CpuFeatures_StringView_IsEquals(a, b);
}
namespace {
std::string ToString(StringView view) { return {view.ptr, view.size}; }
TEST(StackLineReaderTest, Empty) {
auto& fs = GetEmptyFilesystem();
auto* file = fs.CreateFile("/proc/cpuinfo", "");
StackLineReader reader;
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_TRUE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str(""));
}
}
TEST(StackLineReaderTest, ManySmallLines) {
auto& fs = GetEmptyFilesystem();
auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc");
StackLineReader reader;
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("a"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("b"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_TRUE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("c"));
}
}
TEST(StackLineReaderTest, TruncatedLine) {
auto& fs = GetEmptyFilesystem();
auto* file = fs.CreateFile("/proc/cpuinfo", R"(First
Second
More than 16 characters, this will be truncated.
last)");
StackLineReader reader;
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("First"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("Second"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_FALSE(result.full_line);
EXPECT_EQ(result.line, str("More than 16 cha"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_TRUE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str("last"));
}
}
TEST(StackLineReaderTest, TruncatedLines) {
auto& fs = GetEmptyFilesystem();
auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters
Another line that is too long)");
StackLineReader reader;
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_FALSE(result.full_line);
EXPECT_EQ(result.line, str("More than 16 cha"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_FALSE(result.eof);
EXPECT_FALSE(result.full_line);
EXPECT_EQ(result.line, str("Another line tha"));
}
{
const auto result = StackLineReader_NextLine(&reader);
EXPECT_TRUE(result.eof);
EXPECT_TRUE(result.full_line);
EXPECT_EQ(result.line, str(""));
}
}
} // namespace
} // namespace cpu_features

View File

@ -1,192 +0,0 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/string_view.h"
#include "gtest/gtest.h"
namespace cpu_features {
bool operator==(const StringView& a, const StringView& b) {
return CpuFeatures_StringView_IsEquals(a, b);
}
namespace {
TEST(StringViewTest, Empty) {
EXPECT_EQ(kEmptyStringView.ptr, nullptr);
EXPECT_EQ(kEmptyStringView.size, 0);
}
TEST(StringViewTest, Build) {
const auto view = str("test");
EXPECT_EQ(view.ptr[0], 't');
EXPECT_EQ(view.size, 4);
}
TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) {
// Found.
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0);
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1);
// Not found.
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
// Empty.
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1);
}
TEST(StringViewTest, CpuFeatures_StringView_IndexOf) {
// Found.
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0);
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4);
// Not found.
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
// Empty.
EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1);
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1);
}
TEST(StringViewTest, CpuFeatures_StringView_StartsWith) {
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est")));
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
EXPECT_FALSE(
CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
EXPECT_FALSE(
CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test")));
}
TEST(StringViewTest, CpuFeatures_StringView_IsEquals) {
EXPECT_TRUE(
CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test")));
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa")));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
}
TEST(StringViewTest, CpuFeatures_StringView_PopFront) {
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st"));
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test"));
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str(""));
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
}
TEST(StringViewTest, CpuFeatures_StringView_PopBack) {
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te"));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test"));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str(""));
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str(""));
}
TEST(StringViewTest, CpuFeatures_StringView_KeepFront) {
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te"));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str(""));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test"));
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test"));
}
TEST(StringViewTest, CpuFeatures_StringView_Front) {
EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a');
EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a');
}
TEST(StringViewTest, CpuFeatures_StringView_Back) {
EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e');
EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a');
}
TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) {
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")),
str("first middle last"));
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")),
str("first middle last"));
}
TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) {
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);
}
TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
char buf[4];
buf[0] = 'X';
// Empty
CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf));
EXPECT_STREQ(buf, "");
// Less
CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf));
EXPECT_STREQ(buf, "a");
// exact
CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf));
EXPECT_STREQ(buf, "abc");
// More
CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf));
EXPECT_STREQ(buf, "abc");
}
TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
// Find flags at beginning, middle and end.
EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
EXPECT_TRUE(
CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
// Do not match partial flags
EXPECT_FALSE(
CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
}
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {
const StringView line = str(" key : first middle last ");
StringView key, value;
EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
EXPECT_EQ(key, str("key"));
EXPECT_EQ(value, str("first middle last"));
}
TEST(StringViewTest, FailingGetAttributeKeyValue) {
const StringView line = str("key first middle last");
StringView key, value;
EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
}
} // namespace
} // namespace cpu_features

11
crc.c
View File

@ -62,7 +62,7 @@ static void initLookupTables()
} }
} }
uint32_t modesChecksum(const uint8_t *message, int bits) uint32_t modesChecksum(uint8_t *message, int bits)
{ {
uint32_t rem = 0; uint32_t rem = 0;
int i; int i;
@ -197,7 +197,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
maxsize = 0; maxsize = 0;
for (i = 1; i <= max_correct; ++i) { for (i = 1; i <= max_correct; ++i) {
maxsize += combinations(bits, i); // space needed for all i-bit errors maxsize += combinations(bits - 5, i); // space needed for all i-bit errors
} }
#ifdef CRCDEBUG #ifdef CRCDEBUG
@ -210,7 +210,8 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
for (i = 0; i < MODES_MAX_BITERRORS; ++i) for (i = 0; i < MODES_MAX_BITERRORS; ++i)
base_entry.bit[i] = -1; base_entry.bit[i] = -1;
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 0, bits, &base_entry, 0, max_correct); // ignore the first 5 bits (DF type)
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 5, bits, &base_entry, 0, max_correct);
#ifdef CRCDEBUG #ifdef CRCDEBUG
fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize); fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize);
@ -272,7 +273,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect); fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect);
#endif #endif
flagged = flagCollisions(table, usedsize, 112 - bits, 0, bits, 0, 1, max_correct+1, max_detect); flagged = flagCollisions(table, usedsize, 112 - bits, 5, bits, 0, 1, max_correct+1, max_detect);
#ifdef CRCDEBUG #ifdef CRCDEBUG
fprintf(stderr, "Flagged %d collisions for removal.\n", flagged); fprintf(stderr, "Flagged %d collisions for removal.\n", flagged);
@ -340,7 +341,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
if (table[j].errors == i) if (table[j].errors == i)
++count; ++count;
possible = combinations(bits, i); possible = combinations(bits-5, i);
fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible); fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible);
} }

2
crc.h
View File

@ -32,7 +32,7 @@ struct errorinfo {
}; };
void modesChecksumInit(int fixBits); void modesChecksumInit(int fixBits);
uint32_t modesChecksum(const uint8_t *msg, int bitlen); uint32_t modesChecksum(uint8_t *msg, int bitlen);
struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen); struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen);
void modesChecksumFix(uint8_t *msg, struct errorinfo *info); void modesChecksumFix(uint8_t *msg, struct errorinfo *info);

View File

@ -1,8 +1,8 @@
Source: dump1090-fa Source: dump1090-fa
Section: embedded Section: embedded
Priority: extra Priority: extra
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com> Maintainer: Oliver Jowett <oliver@mutability.co.uk>
Build-Depends: debhelper(>=10), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, libncurses5-dev, libbladerf-dev Build-Depends: debhelper(>=9), libusb-1.0-0-dev, pkg-config, cmake, libncurses5-dev
Standards-Version: 3.9.3 Standards-Version: 3.9.3
Homepage: http://www.flightaware.com/ Homepage: http://www.flightaware.com/
Vcs-Git: https://github.com/flightaware/dump1090.git Vcs-Git: https://github.com/flightaware/dump1090.git
@ -19,7 +19,7 @@ Description: transitional dummy package for dump1090
Package: dump1090-fa Package: dump1090-fa
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1 (>= 0.2016.06), adduser, lighttpd Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd
Replaces: dump1090 (<< 3.0) Replaces: dump1090 (<< 3.0)
Breaks: dump1090 (<< 3.0) Breaks: dump1090 (<< 3.0)
Description: ADS-B Ground Station System for RTL-SDR Description: ADS-B Ground Station System for RTL-SDR

View File

@ -0,0 +1,78 @@
#!/bin/bash
### BEGIN INIT INFO
#
# Provides: dump1090-fa
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: dump1090-fa initscript
#
### END INIT INFO
. /lib/lsb/init-functions
DAEMON=/usr/bin/dump1090-fa
PIDFILE=/run/dump1090-fa.pid
WORKDIR=/run/dump1090-fa
RUNAS=dump1090
test -x $DAEMON || exit 5
. /etc/default/dump1090-fa
if [ -f /var/cache/piaware/location.env ]
then
. /var/cache/piaware/location.env
fi
PROG_ARGS="$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $PIAWARE_DUMP1090_LOCATION_OPTIONS \
--write-json /run/dump1090-fa --quiet"
start() {
log_daemon_msg "Starting dump1090-fa server" "dump1090-fa"
mkdir -p $WORKDIR
chown $RUNAS $WORKDIR
/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile $PIDFILE --user $RUNAS --chuid $RUNAS --exec $DAEMON -- $PROG_ARGS
status=$?
log_begin_msg $status
return
}
stop() {
log_daemon_msg "Stopping dump1090-fa server" "dump1090-fa"
/sbin/start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --user $RUNAS
log_end_msg $?
rm -f $PIDFILE
return
}
status() {
echo "no status yet"
return
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|force-reload)
stop && sleep 2 && start
;;
reload)
exit 3
;;
status)
status_of_proc $DAEMON "dump1090-fa server"
;;
*)
echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
exit 2
;;
esac

View File

@ -0,0 +1,5 @@
# This system has dump1090-fa installed, which wants to use RTL2832-based
# digital video dongles in SDR mode via librtlsdr. This file prevents the kernel
# video4linux drivers from loading.
blacklist dvb_usb_rtl28xxu
blacklist rtl2832

View File

@ -0,0 +1,142 @@
# Extracted from the librtlsdr0 package
# because we statically link and don't want the package dependency.
#
# Copyright 2012-2013 Osmocom rtl-sdr project
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# original RTL2832U vid/pid (hama nano, for example)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE:="0666"
# RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE:="0666"
# DigitalNow Quad DVB-T PCI-E card (4x FC0012?)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6680", MODE:="0666"
# Leadtek WinFast DTV Dongle mini D (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6f0f", MODE:="0666"
# Genius TVGo DVB-T03 USB dongle (Ver. B)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0458", ATTRS{idProduct}=="707f", MODE:="0666"
# Terratec Cinergy T Stick Black (rev 1) (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00a9", MODE:="0666"
# Terratec NOXON rev 1 (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b3", MODE:="0666"
# Terratec Deutschlandradio DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b4", MODE:="0666"
# Terratec NOXON DAB Stick - Radio Energy (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b5", MODE:="0666"
# Terratec Media Broadcast DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b7", MODE:="0666"
# Terratec BR DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b8", MODE:="0666"
# Terratec WDR DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b9", MODE:="0666"
# Terratec MuellerVerlag DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c0", MODE:="0666"
# Terratec Fraunhofer DAB Stick (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c6", MODE:="0666"
# Terratec Cinergy T Stick RC (Rev.3) (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d3", MODE:="0666"
# Terratec T Stick PLUS (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d7", MODE:="0666"
# Terratec NOXON rev 2 (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00e0", MODE:="0666"
# PixelView PV-DT235U(RN) (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1554", ATTRS{idProduct}=="5020", MODE:="0666"
# Astrometa DVB-T/DVB-T2 (R828D)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0131", MODE:="0666"
# Compro Videomate U620F (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0620", MODE:="0666"
# Compro Videomate U650F (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0650", MODE:="0666"
# Compro Videomate U680F (E4000)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0680", MODE:="0666"
# GIGABYTE GT-U7300 (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d393", MODE:="0666"
# DIKOM USB-DVBT HD
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d394", MODE:="0666"
# Peak 102569AGPK (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d395", MODE:="0666"
# KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d397", MODE:="0666"
# Zaapa ZT-MINDVBZP (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d398", MODE:="0666"
# SVEON STV20 DVB-T USB & FM (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d39d", MODE:="0666"
# Twintech UT-40 (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a4", MODE:="0666"
# ASUS U3100MINI_PLUS_V2 (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a8", MODE:="0666"
# SVEON STV27 DVB-T USB & FM (FC0013)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3af", MODE:="0666"
# SVEON STV21 DVB-T USB & FM
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3b0", MODE:="0666"
# Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1101", MODE:="0666"
# Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1102", MODE:="0666"
# Dexatek DK 5217 DVB-T Dongle (FC2580)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1103", MODE:="0666"
# MSI DigiVox Micro HD (FC2580)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1104", MODE:="0666"
# Sweex DVB-T USB (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="a803", MODE:="0666"
# GTek T803 (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="b803", MODE:="0666"
# Lifeview LV5TDeluxe (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="c803", MODE:="0666"
# MyGica TD312 (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d286", MODE:="0666"
# PROlectrix DV107669 (FC0012)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d803", MODE:="0666"

View File

@ -12,12 +12,20 @@ export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1 DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk include /usr/share/dpkg/buildflags.mk
override_dh_auto_build: export DUMP1090_VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: /v/p')
# starch's gcc doesn't support the compiler flags needed for ARM-specific starch flavors; SRCNAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p')
# turn off runtime CPU detection
dh_auto_build -- RTLSDR=yes BLADERF=yes HACKRF=no LIMESDR=no DUMP1090_VERSION=$(DEB_VERSION) CPUFEATURES=no install_rtlsdr:
mkdir rtl-sdr-build
cd rtl-sdr-build && cmake ../rtl-sdr -DCMAKE_INSTALL_PREFIX=./install && make install
override_dh_auto_build: install_rtlsdr
dh_auto_build -- RTLSDR=yes BLADERF=no DIALECT=-std=gnu1x DUMP1090_VERSION=$(DUMP1090_VERSION) STATIC=yes RTLSDR_PREFIX=rtl-sdr-build/install
override_dh_auto_test:
dh_auto_test -- DIALECT=-std=gnu1x
override_dh_install: override_dh_install:
dh_install dh_install
@ -25,11 +33,9 @@ override_dh_install:
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
override_dh_installinit: override_dh_clean:
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade dh_clean
rm -fr rtl-sdr-build
override_dh_systemd_start:
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
%: %:
dh $@ --with=systemd dh $@

124
debian/changelog vendored
View File

@ -1,127 +1,3 @@
dump1090-fa (7.2) stable; urgency=medium
* dump1090: Fix Makefile syntax error for Darwin OS build (courtesy @CodyCodeman, PR #170)
* dump1090: set _POSIX_C_SOURCE to fix build failure with uclibc-ng (courtesy @ffontaine, PR #169)
* SkyAware: Remove obselete map interface at /dump1090-fa
* SkyAware: Remove OSM Black & White layer which is no longer in service
-- Eric Tran <eric.tran@flightaware.com> Wed, 09 Mar 2022 20:09:55 -0600
dump1090-fa (7.1) stable; urgency=medium
* Preserve start/upgrade postinst logic for pre 7.1 updates until we support compat 10 behavior
-- Eric Tran <eric.tran@flightaware.com> Wed, 12 Jan 2022 11:37:20 -0600
dump1090-fa (7.0) stable; urgency=medium
* dump1090: Allow env vars (not only command line overrdies) to set CPU_FEATURES_{ARCH,UNAME}
* dump1090: Treat ARCH=arm64 like ARCH=aarch64
* dump1090: Try to respect CFLAGS/CPPFLAGS as far as possible; move required extra flags into a separate var
* dump1090: Adaptive gain - more aggressively re-probe for higher gain after a decrease in gain due to increased noise floor
* dump1090: Cleanup AVR parsing
* SkyAware: Update aircraft db to 20211210
* SkyAware: Cleanup unused Openlayers files
-- Eric Tran <eric.tran@flightaware.com> Mon, 20 Dec 2021 11:00:00 -0600
dump1090-fa (6.1) stable; urgency=medium
* No-change 6.1 release for PiAware 6.1
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 06 Sep 2021 16:06:00 +0800
dump1090-fa (6.0) stable; urgency=medium
* dump1090: Adaptive gain feature with associated dump1090-fa config parameters
* dump1090: Add support for decoding BDS 4,4 - Meteorological Routine Air Report (MRAR) Comm-B messages
* dump1090: Stratux output: include current receiver gain (courtesy @b3nn0, PR #144)
* dump1090: Enable rtlsdr bounce buffers on aarch64 (courtesy @wiedehopf for suggestion)
* dump1090: New default dump1090-fa config file format
* dump1090: Use compat/compat.h for endian-swapping functions in DSP code
* dump1090: Report json write errors, with some rate limiting (fixes issue #129)
* starch: Update starch to upstream commit 0c8249fa4bc523345c156885542e9192e8bf68fd
* SkyAware: restrict overlay rendering to covered areas (reduce source load) (courtesy @wiedehopf, PR #137)
* SkyAware: Fix ignored DisplayUnits in config.js (courtesy @paulyc, PR #76)
* SkyAware: Update aircraft db to 20210817 with better Australian aircraft & types
-- Eric Tran <eric.tran@flightaware.com> Tue, 31 Aug 2021 12:41:06 -0600
dump1090-fa (5.0) stable; urgency=medium
* SkyAware: New Altitude, Speed, Aircraft Ident, and Aircraft Type filters to fine tune the select aircraft you want see
* SkyAware: Ability to toggle visibility of ADS-B, MLAT, UAT, TIS-B, and Other aircraft on SkyAware using the check boxes under the aircraft table
* SkyAware: Ability to show Aircraft Ident labels for all aircraft on your display (found in the View Toggles list in the settings menu)
* SkyAware: A merged SkyAware map of 1090 and UAT aircraft for those with dual 1090/978 setups.
* SkyAware: Direct link on the SkyAware map to go to your My ADS-B statistics page on FlightAware.com or a direct link to claim your receiver if it has not been claimed
* SkyAware: Bold aircraft Idents are used to indicate tail numbers in the aircraft table rather than using the previous prepended underscore syntax
* SkyAware: Default SkyAware link now at <local ip>/skyaware
* dump1090: limesdr: use --gain value if --limesdr-gain is not specified
* dump1090: Switch sample-conversion DSP code to use starch. Provide NEON implementations for ARM when the
hardware supports it. Update 8-bit unsigned zero offset to reflect actual rtlsdr behavior. This gives a
substantial speedup to sample processing for the 12/16-bit case, and a small speedup for the 8-bit case.
Default wisdom provided for arm, aarch64, and x86; see the README for details on generating hardware-
specific wisdom files.
* dump1090: Make console stats display fixed-width (courtesy @gtjoseph)
* dump1090: Add `--json-stats-every` option to control the update cycle of `stats.json`
* dump1090: Don't expire data when reading a capture at full speed via `--ifile`
* dump1090: Count received messages for each DF type, emit in console stats / `stats.json`
* dump1090: Write final stats.json on process exit (mostly useful for `--ifile`)
* dump1090: Attempt to correct DF11/17/18 messages where the DF field itself is damaged. This requires
a lot more CRC checks when receiving messages off-the-air, but slightly increases the decode rate for
DF11/17/18.
* dump1090: Add a `--no-df-fix` option to disable the extra DF field correction, for cases where the extra
messages are not worth the extra CPU
* dump1090: Track recently-seen DF18 addresses, but only count them as recently-seen for DF18 decoding,
not for Mode S / DF17
* dump1090: Support `--stats-every` intervals of less than 1 minute correctly
* dump1090: Don't erroneously consider ICAO 000000 as "recently seen" when decoding
* dump1090: Fix rare hang (1 in 1e9) in FIFO code due to an off-by-one error in normalize_timespec
* dump1090: Correctly expire stale emergency, nac_v data (courtesy @wiedehopf, issue #96)
* dump1090: Fix FIFO bounded memory leak / effective reduction in size of the FIFO, triggered if the
demodulator couldn't keep up with the input rate
* dump1090: Set at least airground = AG_UNCERTAIN for airborne position messages with valid altitudes (issue #113)
* view1090: Interactive mode enhancements to show min/max RSSI, distances (courtesy @gtjoseph, PR #81)
* view1090: Fix table alignment with `--interactive-ttl` > 99 (courtesy @MavEtJu, PR #99)
* view1090: Tweak Mode column to display more data-source info
* view1090: Fix librtlsdr output interfering with interactive mode display (courtesy @VasiliyTurchenko, PR #116)
* general: Fix linking against NetBSD curses library (courtesy @jvanwouw, PR #111)
-- Eric Tran <eric.tran@flightaware.com> Thu, 11 Mar 2021 19:26:07 -6000
dump1090-fa (4.0) stable; urgency=medium
* dump1090: Build support for OS X, FreeBSD, OpenBSD [courtesy @mikenor / @apparentorder on Github, PRs #33 / #38]
* dump1090: Overhaul of SDR / ring buffer / demodulator interface to make it easier to add new SDR types
* dump1090: LimeSDR support [courtesy @Glutton on Github, PR #75]
* dump1090: HackRF support [courtesy @kr105 on Github, PR #57]
* dump1090: Stratux-compatible network output [courtesy @Determinant on Github, PR #61]
* dump1090: Change option syntax for 2-bit correction from --fix --fix (introduced in 3.8.0) to --fix-2bit. Any number of --fix options now yields 1-bit correction.
* dump1090: Support building under GCC 10 (github issue #65)
* dump1090: Include a (disabled by default) example HTTPS configuration [courtesy @jwbernin on Github, PR #66)
* dump1090: For manual builds, if no explicit SDR choice is made, autodetect available libraries via pkg-config
* dump1090: Add a --version command-line option that shows just the version without needing to show the full help screen
* dump1090: Only emit verbose command-line option help if --help is requested, not on any error
* dump1090: List supported device types if --device-type is given without a device type
* dump1090: Removed Debian Wheezy support (distribution is no longer supported upstream)
* dump1090: Remove the "dump1090" Debian metapackage that exists only to provide an upgrade path from very very old installs
* dump1090: Add package profiles to selectively build packages with reduced SDR library dependencies. See the README for details.
* dump1090: If a network port option (--net-bo-port et al) is given on the command line, implicitly enable networking, but don't enable the default port assignments
* dump1090: Provide Mode A / Mode C hit count in aircraft.json
* SkyAware: Update aircraft registry to 20200924
* SkyAware: Update to OpenLayers6
* SkyAware: New basemap layers added/enabled
* SkyAware: Added customizable aircraft table columns
* SkyAware: Added URL query parameter feature to customize display [courtesy @sigwx on Github, PR #58)
* SkyAware: Display registration number in aircraft table if ident is not present
* SkyAware: Fix duplicated Access-Control-Allow-Origin header [courtesy @ianrenton on Github, PR #74)
-- Eric Tran <eric.tran@flightaware.com> Thu, 24 Sep 2020 10:21:00 -6000
dump1090-fa (3.8.1) stable; urgency=medium dump1090-fa (3.8.1) stable; urgency=medium
* SkyAware: Fixed SkyAware banner aspect ratio * SkyAware: Fixed SkyAware banner aspect ratio

2
debian/compat vendored
View File

@ -1 +1 @@
10 9

36
debian/control vendored
View File

@ -1,22 +1,30 @@
Source: dump1090-fa Source: dump1090-fa
Section: embedded Section: embedded
Priority: extra Priority: extra
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com> Maintainer: Oliver Jowett <oliver@mutability.co.uk>
Build-Depends: debhelper(>=10), Build-Depends: debhelper(>=9), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, dh-systemd, libncurses5-dev, libbladerf-dev
librtlsdr-dev <!custom> <rtlsdr>,
libbladerf-dev <!custom> <bladerf>,
libhackrf-dev <!custom> <hackrf>,
liblimesuite-dev <!custom> <limesdr>,
libusb-1.0-0-dev <!custom> <rtlsdr> <bladerf> <hackrf> <limesdr>,
pkg-config, libncurses5-dev
Standards-Version: 3.9.3 Standards-Version: 3.9.3
Homepage: http://www.flightaware.com/ Homepage: http://www.flightaware.com/
Vcs-Git: https://github.com/flightaware/dump1090.git Vcs-Git: https://github.com/edgeofspace/dump1090-fa.git
Package: dump1090
Architecture: all
Depends: dump1090-fa, ${misc:Depends}
Priority: extra
Section: oldlibs
Description: transitional dummy package for dump1090
This is a transitional dummy package to handle upgrades from
the old package name of "dump1090" to the new package name of
"dump1090-fa". It can safely be removed.
Package: dump1090-fa Package: dump1090-fa
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1 (>= 0.2016.06), adduser
Description: FlightAware ADS-B Ground Station System for SDRs Replaces: dump1090 (<< 3.0)
Networked Aviation Mode S / ADS-B decoder/translator with support Breaks: dump1090 (<< 3.0)
for RTL-SDR, BladeRF, HackRF, and LimeSDR software defined radio USB Description: ADS-B Ground Station System for RTL-SDR
device support. Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
defined radio USB device support.
.
This is FlightAware's fork of dump1090-mutability, customized for use
in the PiAware sdcard images.

View File

@ -2,61 +2,14 @@
# This is sourced by /usr/share/dump1090-fa/start-dump1090-fa as a # This is sourced by /usr/share/dump1090-fa/start-dump1090-fa as a
# shellscript fragment. # shellscript fragment.
# If you are using a PiAware sdcard image, this config file is regenerated
# on boot based on the contents of piaware-config.txt; any changes made to this
# file will be lost.
# dump1090-fa won't automatically start unless ENABLED=yes # dump1090-fa won't automatically start unless ENABLED=yes
ENABLED=yes ENABLED=yes
# SDR device type. Use "none" for a net-only configuration RECEIVER_OPTIONS="--device ADSB --gain -10 --ppm 0"
RECEIVER=rtlsdr DECODER_OPTIONS="--max-range 800 --fix"
# serial number or device index of device to use (only needed if there is more than one SDR connected) NET_OPTIONS="--net --net-heartbeat 60 --net-ro-size 1300 --net-ro-interval 0.2 --net-ri-port 0 --net-ro-port 30002 --net-sbs-port 30003 --net-bi-port 30004,30104 --net-bo-port 30005"
RECEIVER_SERIAL= JSON_OPTIONS="--json-location-accuracy 1"
# Initial receiver gain, in dB. If adaptive gain is enabled (see below) the actual gain
# may change over time
RECEIVER_GAIN=60
# Adjust gain to try to achieve optimal dynamic range / noise floor?
ADAPTIVE_DYNAMIC_RANGE=yes
# Target dynamic range in dB (leave blank to autoselect based on SDR type)
ADAPTIVE_DYNAMIC_RANGE_TARGET=
# Reduce gain when loud message bursts from nearby aircraft are seen?
ADAPTIVE_BURST=no
# Gain range to allow when changing gain, in dB (empty = no limit)
ADAPTIVE_MIN_GAIN=
ADAPTIVE_MAX_GAIN=
# Turn on options to reduce load on slower CPUs, at the expense of slightly worse decoder performance.
# Setting "auto" will enable these options only if the CPU appears to be a slow CPU (currently this
# means armv6 only, e.g. Pi Zero)
SLOW_CPU=auto
# Local wisdom file used to select DSP implementations; uses built-in ranking if the file is missing
WISDOM=/etc/dump1090-fa/wisdom.local
# Correct CRC errors where possible
ERROR_CORRECTION=yes
# Receiver location, used for some types of position decoding. Provide the location as
# signed decimal degrees. If not given here, dump1090 will also try to read a receiver
# location from /var/cache/piaware/location.env (written automatically by PiAware, if installed)
RECEIVER_LAT=
RECEIVER_LON=
# Maximum range, in NM. Positions more distant than this are ignored. No limit if not set.
MAX_RANGE=360
# Network ports to listen on for connections
NET_RAW_INPUT_PORTS=
NET_RAW_OUTPUT_PORTS=30002
NET_SBS_OUTPUT_PORTS=30003
NET_BEAST_INPUT_PORTS=30004,30104
NET_BEAST_OUTPUT_PORTS=30005
# Accuracy of location written to JSON output
JSON_LOCATION_ACCURACY=1
# Additional options can be added here:
EXTRA_OPTIONS=""
# If OVERRIDE_OPTIONS is set, only those options are used; all other options
# in this config file are ignored.
OVERRIDE_OPTIONS=""
# This is a marker to make it easier for scripts to identify a v6-style config file
CONFIG_STYLE=6

View File

@ -1,8 +1,3 @@
public_html/* usr/share/skyaware/html public_html/* usr/share/dump1090-fa/html
debian/lighttpd/* etc/lighttpd/conf-available
bladerf/* usr/share/dump1090-fa/bladerf bladerf/* usr/share/dump1090-fa/bladerf
debian/start-dump1090-fa usr/share/dump1090-fa/ debian/start-dump1090-fa usr/share/dump1090-fa/
debian/generate-wisdom usr/share/dump1090-fa/
debian/upgrade-config usr/share/dump1090-fa/
debian/dump1090-fa.default usr/share/dump1090-fa/
starch-benchmark /usr/lib/dump1090-fa/

View File

@ -34,21 +34,44 @@ case "$1" in
# plugdev required for bladeRF USB access # plugdev required for bladeRF USB access
adduser "$RUNAS" plugdev adduser "$RUNAS" plugdev
# set up lighttpd # Make sure the "data" directory is owned by dump1090 so the dump1090-fa process has write access
if dpkg --compare-versions "$2" lt "3.1.0" jsondir="/usr/share/dump1090-fa/html/data"
then if [ ! -d ${jsondir} ]; then
echo "Enabling lighttpd integration.." >&2 echo "Creating directory ${jsondir}..." >&2
lighty-enable-mod dump1090-fa || true mkdir ${jsondir}
fi
if [ -d ${jsondir} ]; then
echo "Changing permissions on ${jsondir}..." >&2
chown ${RUNAS}:nogroup ${jsondir}
chmod 755 ${jsondir}
fi
# only enable the statcache config if there is nothing else around that already # Update apache
# configures it, because lighttpd fails if it's configured twice changed=false
if ! grep -q -E '^\S*server.stat-cache-engine' /etc/lighttpd/conf-enabled/*.conf for apachefile in /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/default-ssl.conf
do
if [ -f ${apachefile} ]; then
echo "Modifying ${apachefile}..." >&2
sed -i '/<\/VirtualHost>/i \
####dump1090-start###\
Alias "/data" "/dump1090-fa/data"\
Alias "/dump1090-fa" "/usr/share/dump1090-fa/html"\
Alias "^/dump1090-fa$" "/dump1090-fa"\
SetEnvIf Request_URI "/dump1090-fa/data/.*\.json$" Header set "Access-Control-Allow-Origin" "*"\
####dump1090-end###' ${apachefile}
changed=true
fi
done
# Restart apache
if $changed
then then
echo "Enabling lighttpd integration (stat cache).." >&2 echo "Restarting Apache..." >&2
lighty-enable-mod dump1090-fa-statcache || true invoke-rc.d apache2 restart || echo "Warning: apache2 failed to restart." >&2
fi
fi fi
# on upgrade, add an ENABLED line if it's not already present # on upgrade, add an ENABLED line if it's not already present
if dpkg --compare-versions "$2" lt-nl "3.7.0" if dpkg --compare-versions "$2" lt-nl "3.7.0"
then then
@ -63,36 +86,14 @@ case "$1" in
fi fi
fi fi
# on upgrade from pre-6.0, update the defaults file to the new syntax # enabling and starting the dump1090-fa service
if dpkg --compare-versions "$2" lt-nl "6.0" echo "Unmasking the dump1090-fa service..." >&2
then systemctl unmask dump1090-fa
if [ -f /etc/default/dump1090-fa ] echo "Enabling the dump1090-fa service..." >&2
then systemctl enable dump1090-fa
echo "Trying to upgrade existing config to new syntax.." >&2 echo "Starting the dump1090-fa service..." >&2
/usr/share/dump1090-fa/upgrade-config /etc/default/dump1090-fa /usr/share/dump1090-fa/dump1090-fa.default \ systemctl restart dump1090-fa
|| echo "Something went wrong upgrading the config; your config may be broken. Sorry!" >&1
fi
fi
if dpkg --compare-versions "$2" le "5.0"
then
echo "Enabling lighttpd skyaware module.." >&2
lighty-enable-mod skyaware || true
fi
# dump1090-fa lighttpd module deprecated in 7.2
if dpkg --compare-versions "$2" lt "7.2"
then
if [ -e /etc/lighttpd/conf-enabled/89-dump1090-fa.conf ]
then
echo "Disabling deprecated lighttpd dump1090-fa module..." >&2
lighty-disable-mod dump1090-fa || true
fi
fi
echo "Restarting lighttpd.." >&2
invoke-rc.d lighttpd restart || true
;; ;;
abort-upgrade|abort-remove|abort-deconfigure) abort-upgrade|abort-remove|abort-deconfigure)

View File

@ -26,24 +26,21 @@ case "$1" in
remove) remove)
changed=false changed=false
if [ -e /etc/lighttpd/conf-enabled/89-dump1090-fa.conf ]
then
echo "Disabling lighttpd integration.." >&2
lighty-disable-mod dump1090-fa || true
changed=true
fi
if [ -e /etc/lighttpd/conf-enabled/88-dump1090-fa-statcache.conf ] for apachefile in /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/default-ssl.conf
then do
echo "Disabling lighttpd integration (stat cache).." >&2 if [ -f ${apachefile} ]; then
lighty-disable-mod dump1090-fa-statcache || true echo "Modifying apache file ${apachefile}..." >&2
sed -i '/^[ \t]*#*dump1090-start#*/,/^[ \t]*#*dump1090-end#*/{/^[ \t]*#*dump1090-start#*/!{/^[ \t]*#*dump1090-end#*/!d}}' ${apachefile}
sed -i '/[ \t]*#*dump1090-start#*/,/^[ \t]*#*dump1090-end#*/d' ${apachefile}
changed=true changed=true
fi fi
done
if $changed if $changed
then then
echo "Restarting lighttpd.." >&2 echo "Restarting Apache..." >&2
invoke-rc.d lighttpd restart || echo "Warning: lighttpd failed to restart." >&2 invoke-rc.d apache2 restart || echo "Warning: apache2 failed to restart." >&2
fi fi
;; ;;

View File

@ -10,7 +10,7 @@ After=network.target
User=dump1090 User=dump1090
RuntimeDirectory=dump1090-fa RuntimeDirectory=dump1090-fa
RuntimeDirectoryMode=0755 RuntimeDirectoryMode=0755
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json /usr/share/dump1090-fa/html/data --quiet
SyslogIdentifier=dump1090-fa SyslogIdentifier=dump1090-fa
Type=simple Type=simple
Restart=on-failure Restart=on-failure

View File

@ -1,20 +0,0 @@
#!/bin/sh -e
# This script generates a machine-specific wisdom file for dump1090-fa
# (containing information about which DSP implementations are fastest)
WORKDIR=$(mktemp -t -d wisdom.XXXXXX)
echo "Benchmarking .. this will take a while." >&2
# generate initial wisdom so that twopass implementations have something to work with
echo "First pass: generating $WORKDIR/wisdom.initial" >&2
/usr/lib/dump1090-fa/starch-benchmark -i 5 -o $WORKDIR/wisdom.initial magnitude_uc8 magnitude_uc8_aligned mean_power_u16 mean_power_u16_aligned
# generate the real wisdom
echo "Second pass: generating $WORKDIR/wisdom.local" >&2
/usr/lib/dump1090-fa/starch-benchmark -i 5 -r $WORKDIR/wisdom.initial -o $WORKDIR/wisdom.local
echo "Wisdom written to $WORKDIR/wisdom.local" >&2
echo "Copy this file to /etc/dump1090-fa/wisdom.local" >&2
echo "(and restart dump1090-fa) to start using it." >&2

View File

@ -1,4 +0,0 @@
# The stat cache must be disabled, as aircraft.json changes
# frequently and lighttpd's stat cache often ends up with the
# wrong content length.
server.stat-cache-engine = "disable"

View File

@ -1,75 +0,0 @@
# Allows access to the static files that provide the dump1090 map view,
# and also to the dynamically-generated json parts that contain aircraft
# data and are periodically written by the dump1090 daemon.
# Enable alias module
#
## This module is normally already enabled in lighttpd, so you should not
## need to uncommment this line.
## There are some cases (e.g. when installing this on a Raspberry Pi
## that runs PiHole) in which the module has been removed from the
## default configuration, and the dump1090-fa web interface no longer
## loads properly.
## If this is what you are experiencing, or if you see messages in your
## error log like:
## (server.c.1493) WARNING: unknown config-key: alias.url (ignored)
## then uncommenting this line and then restarting lighttpd could fix
## the issue.
## This is not enabled by default as standard lighttpd will not start if
## modules are loaded multiple times.
#
# server.modules += ( "mod_alias" )
alias.url += (
"/skyaware/data/" => "/run/dump1090-fa/",
"/skyaware/data-978/" => "/run/skyaware978/",
"/skyaware/" => "/usr/share/skyaware/html/"
)
# redirect the slash-less URL
url.redirect += (
"^/skyaware$" => "/skyaware/"
)
# Listen on port 8080 and serve the map there, too.
$SERVER["socket"] == ":8080" {
alias.url += (
"/data/" => "/run/dump1090-fa/",
"/data-978/" => "/run/skyaware978/",
"/" => "/usr/share/skyaware/html/"
)
}
# Add CORS header
server.modules += ( "mod_setenv" )
$HTTP["url"] =~ "^/skyaware/data/.*\.json$" {
setenv.set-response-header = ( "Access-Control-Allow-Origin" => "*" )
}
# Uncomment this section to enable SSL traffic (HTTPS) - especially useful
# for .dev domains
## Listen on 8443 for SSL connections
#server.modules += ( "mod_openssl" )
#$HTTP["host"] == "piaware.example.com" {
# $SERVER["socket"] == ":8443" {
# ssl.engine = "enable"
# ssl.pemfile = "/etc/ssl/certs/combined.pem"
# ssl.ca-file = "/etc/ssl/certs/fullchain.cer"
# ssl.honor-cipher-order = "enable"
# ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
# ssl.use-sslv2 = "disable"
# ssl.use-sslv3 = "disable"
#
# alias.url += (
# "/data/" => "/run/dump1090-fa/",
# "/" => "/usr/share/skyware/html/"
# )
# }
#}
#
## Redirect HTTP to HTTPS
#$HTTP["scheme"] == "http" {
# $HTTP["host"] =~ ".*" {
# url.redirect = (".*" => "https://%0$0")
# }
#}

39
debian/rules vendored
View File

@ -14,38 +14,13 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1 DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk include /usr/share/dpkg/default.mk
ifeq (,$(filter custom,$(DEB_BUILD_PROFILES))) ifeq ($(DEB_HOST_ARCH),armhf)
# Standard build # Assume a Pi-like target, where using an 8-bit table is a fairly big win over the float path
RTLSDR = yes CPPFLAGS += -DSC16Q11_TABLE_BITS=8
BLADERF = yes
HACKRF = yes
LIMESDR = yes
else
# Custom build
ifneq (,$(filter rtlsdr,$(DEB_BUILD_PROFILES)))
RTLSDR = yes
else
RTLSDR = no
endif
ifneq (,$(filter bladerf,$(DEB_BUILD_PROFILES)))
BLADERF = yes
else
BLADERF = no
endif
ifneq (,$(filter hackrf,$(DEB_BUILD_PROFILES)))
HACKRF = yes
else
HACKRF = no
endif
ifneq (,$(filter limesdr,$(DEB_BUILD_PROFILES)))
LIMESDR = yes
else
LIMESDR = no
endif
endif endif
override_dh_auto_build: override_dh_auto_build:
dh_auto_build -- RTLSDR=$(RTLSDR) BLADERF=$(BLADERF) HACKRF=$(HACKRF) LIMESDR=$(LIMESDR) DUMP1090_VERSION=$(DEB_VERSION) dh_auto_build -- RTLSDR=yes BLADERF=yes DUMP1090_VERSION=$(DEB_VERSION)
override_dh_install: override_dh_install:
dh_install dh_install
@ -53,11 +28,5 @@ override_dh_install:
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
override_dh_installinit:
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade
override_dh_systemd_start:
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
%: %:
dh $@ --with=systemd dh $@ --with=systemd

View File

@ -15,93 +15,19 @@ then
. /var/cache/piaware/location.env . /var/cache/piaware/location.env
fi fi
if [ "$ENABLED" != "yes" ] if [ "x$ENABLED" != "xyes" ]
then then
echo "dump1090-fa not enabled in /etc/default/dump1090-fa" >&2 echo "dump1090-fa not enabled in /etc/default/dump1090-fa" >&2
exit 64 exit 64
fi fi
# process options if [ -n "$PIAWARE_LAT" -a -n "$PIAWARE_LON" ]
# if there's no CONFIG_STYLE, infer a version
if [ -z "$CONFIG_STYLE" ]
then then
if [ -n "$RECEIVER_OPTIONS" -o -n "$DECODER_OPTIONS" -o -n "$NET_OPTIONS" -o -n "$JSON_OPTIONS" ] POSITION="--lat $PIAWARE_LAT --lon $PIAWARE_LON"
then
CONFIG_STYLE=5
else
CONFIG_STYLE=6
fi
fi fi
is_slow_cpu() { exec /usr/bin/dump1090-fa \
case "$SLOW_CPU" in $RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $POSITION \
yes) return 0 ;; "$@"
auto)
case $(uname -m) in
armv6*) return 0 ;;
*) return 1 ;;
esac
;;
*) return 1 ;;
esac
}
if [ "$CONFIG_STYLE" = "5" ]
then
# old style config file
echo "/etc/default/dump1090-fa is using the old config style, please consider updating it" >&2
OPTS="$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS"
elif [ -n "$OVERRIDE_OPTIONS" ]
then
# ignore all other settings, use only provided options
OPTS="$OVERRIDE_OPTIONS"
else
# build a list of options based on config settings
OPTS=""
if [ "${RECEIVER:-none}" = "none" ]
then
OPTS="$OPTS --device-type none"
else
if [ -n "$RECEIVER" ]; then OPTS="$OPTS --device-type $RECEIVER"; fi
if [ -n "$RECEIVER_SERIAL" ]; then OPTS="$OPTS --device-index $RECEIVER_SERIAL"; fi
if [ -n "$RECEIVER_GAIN" ]; then OPTS="$OPTS --gain $RECEIVER_GAIN"; fi
if [ -n "$WISDOM" -a -f "$WISDOM" ]; then OPTS="$OPTS --wisdom $WISDOM"; fi
if [ "$ADAPTIVE_DYNAMIC_RANGE" = "yes" ]; then OPTS="$OPTS --adaptive-range"; fi
if [ -n "$ADAPTIVE_DYNAMIC_RANGE_TARGET" ]; then OPTS="$OPTS --adaptive-range-target $ADAPTIVE_DYNAMIC_RANGE_TARGET"; fi
if [ "$ADAPTIVE_BURST" = "yes" ]; then OPTS="$OPTS --adaptive-burst"; fi
if [ -n "$ADAPTIVE_MIN_GAIN" ]; then OPTS="$OPTS --adaptive-min-gain $ADAPTIVE_MIN_GAIN"; fi
if [ -n "$ADAPTIVE_MAX_GAIN" ]; then OPTS="$OPTS --adaptive-max-gain $ADAPTIVE_MAX_GAIN"; fi
if is_slow_cpu
then
OPTS="$OPTS --adaptive-duty-cycle 10 --no-fix-df"
fi
fi
if [ "$ERROR_CORRECTION" = "yes" ]; then OPTS="$OPTS --fix"; fi
if [ -n "$RECEIVER_LAT" -a -n "$RECEIVER_LON" ]; then
OPTS="$OPTS --lat $RECEIVER_LAT --lon $RECEIVER_LON"
elif [ -n "$PIAWARE_LAT" -a -n "$PIAWARE_LON" ]; then
OPTS="$OPTS --lat $PIAWARE_LAT --lon $PIAWARE_LON"
fi
if [ -n "$MAX_RANGE" ]; then OPTS="$OPTS --max-range $MAX_RANGE"; fi
if [ -n "$NET_RAW_INPUT_PORTS" ]; then OPTS="$OPTS --net-ri-port $NET_RAW_INPUT_PORTS"; fi
if [ -n "$NET_RAW_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-ro-port $NET_RAW_OUTPUT_PORTS"; fi
if [ -n "$NET_SBS_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-sbs-port $NET_SBS_OUTPUT_PORTS"; fi
if [ -n "$NET_BEAST_INPUT_PORTS" ]; then OPTS="$OPTS --net-bi-port $NET_BEAST_INPUT_PORTS"; fi
if [ -n "$NET_BEAST_OUTPUT_PORTS" ]; then OPTS="$OPTS --net-bo-port $NET_BEAST_OUTPUT_PORTS"; fi
if [ -n "$JSON_LOCATION_ACCURACY" ]; then OPTS="$OPTS --json-location-accuracy $JSON_LOCATION_ACCURACY"; fi
if [ -n "$EXTRA_OPTIONS" ]; then OPTS="$OPTS $EXTRA_OPTIONS"; fi
fi
exec /usr/bin/dump1090-fa --quiet $OPTS "$@"
# exec failed, do not restart # exec failed, do not restart
exit 64 exit 64

187
debian/upgrade-config vendored
View File

@ -1,187 +0,0 @@
#!/bin/sh
# This script runs during upgrade from pre-6.0 to try to
# update /etc/default/dump1090-fa to the new-style
# config.
if [ $# -lt 2 ]
then
echo "syntax: $0 path-to-config path-to-package-defaults" >&2
exit 2
fi
OLDCONFIG="$1"
NEWCONFIG="${OLDCONFIG}.v6-upgrade"
BACKUPCONFIG="${OLDCONFIG}.pre-v6-upgrade"
PACKAGECONFIG="$2"
if [ ! -f $OLDCONFIG ]
then
echo "$OLDCONFIG does not exist, nothing to upgrade" >&2
exit 0
fi
if [ ! -f $PACKAGECONFIG ]
then
echo "$PACKAGECONFIG does not exist, cannot continue" >&2
exit 1
fi
if [ -f $BACKUPCONFIG ]
then
echo "$BACKUPCONFIG already exists, I'm not going to clobber it" >&2
exit 1
fi
# set some assumed defaults (5.0 dump1090 binary defaults if no command-line options are given)
ENABLED="no"
RECEIVER="rtlsdr"
RECEIVER_SERIAL=""
RECEIVER_GAIN="50"
WISDOM=""
ERROR_CORRECTION="no"
MAX_RANGE=""
NET_RAW_INPUT_PORTS="30001"
NET_RAW_OUTPUT_PORTS="30002"
NET_SBS_OUTPUT_PORTS="30003"
NET_BEAST_INPUT_PORTS="30004,30104"
NET_BEAST_OUTPUT_PORTS="30005"
EXTRAS_NET_RO_SIZE="0"
EXTRAS_NET_RO_INTERVAL="0"
EXTRAS_NET_HEARTBEAT="60"
# read the old config
. "$OLDCONFIG"
# if there's no CONFIG_STYLE, infer a version
if [ -z "$CONFIG_STYLE" ]
then
if [ -n "$RECEIVER_OPTIONS" -o -n "$DECODER_OPTIONS" -o -n "$NET_OPTIONS" -o -n "$JSON_OPTIONS" ]
then
CONFIG_STYLE=5
else
CONFIG_STYLE=6
fi
fi
# process all the options from the old config file and accumulate settings in env vars
process_v5_options() {
while [ $# -gt 0 ]
do
opt="$1"
shift
case "$opt" in
--device-type) RECEIVER="$1"; shift ;;
--device-index) RECEIVER_SERIAL="$1"; shift ;;
--gain) RECEIVER_GAIN="$1"; shift ;;
--max-range) MAX_RANGE="$1"; shift ;;
--fix) ERROR_CORRECTION="yes" ;;
--net) ;;
--net-ri-port) NET_RAW_INPUT_PORTS="$1"; shift ;;
--net-ro-port) NET_RAW_OUTPUT_PORTS="$1"; shift ;;
--net-sbs-port) NET_SBS_OUTPUT_PORTS="$1"; shift ;;
--net-bi-port) NET_BEAST_INPUT_PORTS="$1"; shift ;;
--net-bo-port) NET_BEAST_OUTPUT_PORTS="$1"; shift ;;
--json-location-accuracy) JSON_LOCATION_ACCURACY="$1"; shift ;;
--wisdom) WISDOM="$1"; shift ;;
--ppm) EXTRAS_PPM="$1"; shift ;;
--net-heartbeat) EXTRAS_NET_HEARTBEAT="$1"; shift ;;
--net-ro-size) EXTRAS_NET_RO_SIZE="$1"; shift ;;
--net-ro-interval) EXTRAS_NET_RO_INTERVAL="$1"; shift ;;
*) EXTRA_OPTIONS="$EXTRA_OPTIONS ${opt}" ;;
esac
done
# update EXTRA_OPTIONS for any non-default special settings
if [ "${EXTRAS_PPM:-0}" != "0" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --ppm $EXTRAS_PPM"; fi
if [ "${EXTRAS_NET_HEARTBEAT:-60}" != "60" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-heartbeat $EXTRAS_NET_HEARTBEAT"; fi
if [ "${EXTRAS_NET_RO_SIZE:-1300}" != "1300" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-ro-size $EXTRAS_NET_RO_SIZE"; fi
if [ "${EXTRAS_NET_RO_INTERVAL:-1300}" != "0.2" ]; then EXTRA_OPTIONS="$EXTRA_OPTIONS --net-ro-interval $EXTRAS_NET_RO_INTERVAL"; fi
# special case for device index 0 (the default)
if [ "${RECEIVER_SERIAL}" = "0" ]; then RECEIVER_SERIAL=""; fi
# special case for gain -10 -> gain 60
if [ "${RECEIVER_GAIN}" = "-10" ]; then RECEIVER_GAIN="60"; fi
# special case for ports set to zero (new config uses a blank entry for that)
if [ "${NET_RAW_INPUT_PORTS}" = "0" ]; then NET_RAW_INPUT_PORTS=""; fi
if [ "${NET_RAW_OUTPUT_PORTS}" = "0" ]; then NET_RAW_OUTPUT_PORTS=""; fi
if [ "${NET_SBS_INPUT_PORTS}" = "0" ]; then NET_SBS_OUTPUT_PORTS=""; fi
if [ "${NET_BEAST_INPUT_PORTS}" = "0" ]; then NET_BEAST_INPUT_PORTS=""; fi
if [ "${NET_BEAST_OUTPUT_PORTS}" = "0" ]; then NET_BEAST_OUTPUT_PORTS=""; fi
}
SEDSCRIPT=$(mktemp -t dump1090XXX.sed)
if [ "$CONFIG_STYLE" = "5" ]
then
echo "Generating a v6-style config from the v5-style config in $OLDCONFIG" >&2
# nb: all values either derived from env vars or the package defaults
process_v5_options $RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS
FROMCONFIG=$PACKAGECONFIG
cat >>$SEDSCRIPT <<EOF
s@^ENABLED=.*@ENABLED=${ENABLED}@
s@^RECEIVER=.*@RECEIVER=${RECEIVER}@
s@^RECEIVER_SERIAL=.*@RECEIVER_SERIAL="${RECEIVER_SERIAL}"@
s@^RECEIVER_GAIN=.*@RECEIVER_GAIN=${RECEIVER_GAIN}@
s@^WISDOM=.*@WISDOM=${WISDOM}@
s@^ERROR_CORRECTION=.*@ERROR_CORRECTION=${ERROR_CORRECTION}@
s@^MAX_RANGE=.*@MAX_RANGE=${MAX_RANGE}@
s@^NET_RAW_INPUT_PORTS=.*@NET_RAW_INPUT_PORTS=${NET_RAW_INPUT_PORTS}@
s@^NET_RAW_OUTPUT_PORTS=.*@NET_RAW_OUTPUT_PORTS=${NET_RAW_OUTPUT_PORTS}@
s@^NET_SBS_OUTPUT_PORTS=.*@NET_SBS_OUTPUT_PORTS=${NET_SBS_OUTPUT_PORTS}@
s@^NET_BEAST_INPUT_PORTS=.*@NET_BEAST_INPUT_PORTS=${NET_BEAST_INPUT_PORTS}@
s@^NET_BEAST_OUTPUT_PORTS=.*@NET_BEAST_OUTPUT_PORTS=${NET_BEAST_OUTPUT_PORTS}@
s@^JSON_LOCATION_ACCURACY=.*@JSON_LOCATION_ACCURACY=${JSON_LOCATION_ACCURACY}@
s@^EXTRA_OPTIONS=.*@EXTRA_OPTIONS="$EXTRA_OPTIONS"@
EOF
else
# Existing config file doesn't seem to be a v5, just turn off adaptive gain settings
# as this is an upgrade but otherwise leave it unchanged. (This happens when
# there were no changes made by the user to the config file before upgrading; dpkg
# will install the new v6 default config file automatically in that case)
FROMCONFIG=$OLDCONFIG
fi
# All upgrades get adaptive gain defaulting to off, to preserve the behaviour of
# existing installs. New installs using the package defaults will default to on.
echo "Disabling adaptive gain in $OLDCONFIG as this is an upgrade from pre-v6" >&2
cat >>$SEDSCRIPT <<EOF
s@^ADAPTIVE_DYNAMIC_RANGE=.*@ADAPTIVE_DYNAMIC_RANGE=no@
s@^ADAPTIVE_BURST=.*@ADAPTIVE_BURST=no@
EOF
# substitute into the config file template to generate our customized config
if ! sed -f $SEDSCRIPT <$FROMCONFIG >$NEWCONFIG
then
echo "Something went wrong trying to upgrade $OLDCONFIG, giving up.." >&2
exit 1
fi
rm $SEDSCRIPT
# back up the old config and install the new config
if ! cp -p $OLDCONFIG $BACKUPCONFIG
then
echo "Something went wrong trying to back up $OLDCONFIG, giving up.." >&2
exit 1
fi
if ! mv $NEWCONFIG $OLDCONFIG
then
echo "Something went wrong trying to install the new version of $NEWCONFIG, giving up.." >&2
exit 1
fi
# all good
cat >&2 <<EOF
Upgraded existing config $OLDCONFIG to the new config syntax.
Please doublecheck that it looks ok!
The old config file has been preserved at $BACKUPCONFIG
EOF
exit 0

View File

@ -58,40 +58,6 @@ static inline int slice_phase4(uint16_t *m) {
return m[0] + 5 * m[1] - 5 * m[2] - m[3]; return m[0] + 5 * m[1] - 5 * m[2] - m[3];
} }
static uint32_t valid_df_short_bitset; // set of acceptable DF values for short messages
static uint32_t valid_df_long_bitset; // set of acceptable DF values for long messages
static uint32_t generate_damage_set(uint8_t df, unsigned damage_bits)
{
uint32_t result = (1 << df);
if (!damage_bits)
return result;
for (unsigned bit = 0; bit < 5; ++bit) {
unsigned damaged_df = df ^ (1 << bit);
result |= generate_damage_set(damaged_df, damage_bits - 1);
}
return result;
}
static void init_bitsets()
{
// DFs that we directly understand without correction
valid_df_short_bitset = (1 << 0) | (1 << 4) | (1 << 5) | (1 << 11);
valid_df_long_bitset = (1 << 16) | (1 << 17) | (1 << 18) | (1 << 20) | (1 << 21);
if (Modes.enable_df24)
valid_df_long_bitset |= (1 << 24) | (1 << 25) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31);
// if we can also repair DF damage, include those corrections
if (Modes.fix_df && Modes.nfix_crc) {
valid_df_short_bitset |= generate_damage_set(11, 1);
valid_df_long_bitset |= generate_damage_set(17, Modes.nfix_crc);
valid_df_long_bitset |= generate_damage_set(18, Modes.nfix_crc);
}
}
// //
// Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz, // Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz,
// try to demodulate some Mode S messages. // try to demodulate some Mode S messages.
@ -103,35 +69,17 @@ void demodulate2400(struct mag_buf *mag)
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg; unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
uint32_t j; uint32_t j;
static unsigned last_message_end = 0;
// initialize bitsets on first call
if (!valid_df_short_bitset)
init_bitsets();
if (mag->flags & MAGBUF_DISCONTINUOUS) {
// gap, start from the very beginning
last_message_end = 0;
}
unsigned char *bestmsg; unsigned char *bestmsg;
int bestscore, bestphase; int bestscore, bestphase;
// maximum lookahead we use
assert(mag->overlap >= 19 + 1 + 269);
uint16_t *m = mag->data; uint16_t *m = mag->data;
uint32_t mlen = mag->validLength - mag->overlap; uint32_t mlen = mag->length;
uint64_t sum_scaled_signal_power = 0; uint64_t sum_scaled_signal_power = 0;
msg = msg1; msg = msg1;
// sanity check for (j = 0; j < mlen; j++) {
if (last_message_end > mlen)
last_message_end = mlen;
for (j = last_message_end; j < mlen; j++) {
uint16_t *preamble = &m[j]; uint16_t *preamble = &m[j];
int high; int high;
uint32_t base_signal, base_noise; uint32_t base_signal, base_noise;
@ -219,10 +167,10 @@ void demodulate2400(struct mag_buf *mag)
// try all phases // try all phases
Modes.stats_current.demod_preambles++; Modes.stats_current.demod_preambles++;
bestmsg = NULL; bestscore = SR_NOT_SET; bestphase = -1; bestmsg = NULL; bestscore = -2; bestphase = -1;
for (try_phase = 4; try_phase <= 8; ++try_phase) { for (try_phase = 4; try_phase <= 8; ++try_phase) {
uint16_t *pPtr; uint16_t *pPtr;
int phase, score; int phase, i, score, bytelen;
// Decode all the next 112 bits, regardless of the actual message // Decode all the next 112 bits, regardless of the actual message
// size. We'll check the actual message type later // size. We'll check the actual message type later
@ -230,8 +178,8 @@ void demodulate2400(struct mag_buf *mag)
pPtr = &m[j+19] + (try_phase/5); pPtr = &m[j+19] + (try_phase/5);
phase = try_phase % 5; phase = try_phase % 5;
unsigned bytelen = 1; bytelen = MODES_LONG_MSG_BYTES;
for (unsigned i = 0; i < bytelen; ++i) { for (i = 0; i < bytelen; ++i) {
uint8_t theByte = 0; uint8_t theByte = 0;
switch (phase) { switch (phase) {
@ -313,26 +261,23 @@ void demodulate2400(struct mag_buf *mag)
} }
msg[i] = theByte; msg[i] = theByte;
if (i == 0) { if (i == 0) {
// inspect DF field early, only continue processing switch (msg[0] >> 3) {
// messages where the DF appears valid case 0: case 4: case 5: case 11:
unsigned df = theByte >> 3; bytelen = MODES_SHORT_MSG_BYTES; break;
if (valid_df_long_bitset & (1 << df))
bytelen = MODES_LONG_MSG_BYTES;
else if (valid_df_short_bitset & (1 << df))
bytelen = MODES_SHORT_MSG_BYTES;
}
}
if (bytelen == 1) { case 16: case 17: case 18: case 20: case 21: case 24:
// rejected early by the DF filter break;
Modes.stats_current.demod_rejected_bad++;
continue; default:
bytelen = 1; // unknown DF, give up immediately
break;
}
}
} }
// Score the mode S message and see if it's any good. // Score the mode S message and see if it's any good.
score = scoreModesMessage(msg); score = scoreModesMessage(msg, i*8);
if (score > bestscore) { if (score > bestscore) {
// new high score! // new high score!
bestmsg = msg; bestmsg = msg;
@ -347,8 +292,8 @@ void demodulate2400(struct mag_buf *mag)
} }
// Do we have a candidate? // Do we have a candidate?
if (bestscore < SR_ACCEPT_THRESHOLD) { if (bestscore < 0) {
if (bestscore >= SR_UNKNOWN_THRESHOLD) if (bestscore == -1)
Modes.stats_current.demod_rejected_unknown_icao++; Modes.stats_current.demod_rejected_unknown_icao++;
else else
Modes.stats_current.demod_rejected_bad++; Modes.stats_current.demod_rejected_bad++;
@ -371,12 +316,18 @@ void demodulate2400(struct mag_buf *mag)
mm.score = bestscore; mm.score = bestscore;
// Decode the received message // Decode the received message
if (decodeModesMessage(&mm, bestmsg) < 0) { {
int result = decodeModesMessage(&mm, bestmsg);
if (result < 0) {
if (result == -1)
Modes.stats_current.demod_rejected_unknown_icao++;
else
Modes.stats_current.demod_rejected_bad++; Modes.stats_current.demod_rejected_bad++;
continue; continue;
} else { } else {
Modes.stats_current.demod_accepted[mm.correctedbits]++; Modes.stats_current.demod_accepted[mm.correctedbits]++;
} }
}
// measure signal power // measure signal power
{ {
@ -402,21 +353,13 @@ void demodulate2400(struct mag_buf *mag)
Modes.stats_current.strong_signal_count++; // signal power above -3dBFS Modes.stats_current.strong_signal_count++; // signal power above -3dBFS
} }
// Feed "empty" sample to adaptive gain logic
if (j > last_message_end)
adaptive_update(&m[last_message_end], j - last_message_end, NULL);
// Feed message samples to adaptive gain logic, update end pointer
last_message_end = j + (msglen + 8) * 12/5;
adaptive_update(&m[j], last_message_end - j, &mm);
// Skip over the message: // Skip over the message:
// (we actually skip to 8 bits before the end of the message, // (we actually skip to 8 bits before the end of the message,
// because we can often decode two messages that *almost* collide, // because we can often decode two messages that *almost* collide,
// where the preamble of the second message clobbered the last // where the preamble of the second message clobbered the last
// few bits of the first message, but the message bits didn't // few bits of the first message, but the message bits didn't
// overlap) // overlap)
j = last_message_end - 8*12/5; j += msglen*12/5;
// Pass data to the next layer // Pass data to the next layer
useModesMessage(&mm); useModesMessage(&mm);
@ -425,23 +368,11 @@ void demodulate2400(struct mag_buf *mag)
/* update noise power */ /* update noise power */
{ {
double sum_signal_power = sum_scaled_signal_power / 65535.0 / 65535.0; double sum_signal_power = sum_scaled_signal_power / 65535.0 / 65535.0;
Modes.stats_current.noise_power_sum += (mag->mean_power * mlen - sum_signal_power); Modes.stats_current.noise_power_sum += (mag->mean_power * mag->length - sum_signal_power);
Modes.stats_current.noise_power_count += mlen; Modes.stats_current.noise_power_count += mag->length;
}
} }
// feed trailing empty samples to adaptive gain logic
if (last_message_end < mlen) {
// trailing data from end of last message to start of overlap;
// on the next pass, start from the start of the overlap
adaptive_update(&m[last_message_end], mlen - last_message_end, NULL);
last_message_end = 0;
} else {
// last decoded message runs into the overlap region;
// on the next pass, start at the right place in the overlap;
// no trailing data to pass this time
last_message_end -= mlen;
}
}
#ifdef MODEAC_DEBUG #ifdef MODEAC_DEBUG
@ -540,7 +471,7 @@ void demodulate2400AC(struct mag_buf *mag)
{ {
struct modesMessage mm; struct modesMessage mm;
uint16_t *m = mag->data; uint16_t *m = mag->data;
uint32_t mlen = mag->validLength - mag->overlap; uint32_t mlen = mag->length;
unsigned f1_sample; unsigned f1_sample;
memset(&mm, 0, sizeof(mm)); memset(&mm, 0, sizeof(mm));
@ -621,7 +552,7 @@ void demodulate2400AC(struct mag_buf *mag)
// F2 is 20.3us / 14 bit periods after F1 // F2 is 20.3us / 14 bit periods after F1
unsigned f2_clock = f1_clock + (87 * 14); unsigned f2_clock = f1_clock + (87 * 14);
unsigned f2_sample = f2_clock / 25; unsigned f2_sample = f2_clock / 25;
assert(f2_sample < mlen + mag->overlap); assert(f2_sample < mlen + Modes.trailing_samples);
if (!(m[f2_sample-1] < m[f2_sample+0])) if (!(m[f2_sample-1] < m[f2_sample+0]))
continue; continue;

Some files were not shown because too many files have changed in this diff Show More