Commit Graph

562 Commits

Author SHA1 Message Date
Christopher Haster 316b019f41 In CI, determine loop devices dynamically to avoid conflicts with Ubuntu snaps
Introduced when updating CI to Ubuntu 20.04, Ubuntu snaps consume
loop devices, which conflict with out assumption that /dev/loop0
will always be unused. Changed to request a dynamic loop device from
losetup, though it would have been nice if Ubuntu snaps allocated
from the last device or something.
2022-03-20 03:39:23 -05:00
Christopher Haster 8475c8064d Limit ./scripts/structs.py to report structs in local .h files
This requires parsing an additional section of the dwarfinfo (--dwarf=rawlines)
to get the declaration file info.

---

Interpreting the results of ./scripts/structs.py reporting is a bit more
complicated than other scripts, structs aren't used in a consistent
manner so the cost of a large struct depends on the context in which it
is used.

But that being said, there really isn't much reason to report
internal-only structs. These structs really only exist for type-checking
in internal algorithms, and their cost will end up reflected in other RAM
measurements, either stack, heap, or other.
2022-03-20 03:39:23 -05:00
Christopher Haster 563af5f364 Cleaned up make clean 2022-03-20 03:39:23 -05:00
Christopher Haster 3b495bab79 Fixed spurious CI failure caused by multiple writers to .o files
GCC is a bit frustrating here, it really wants to generate every file in
a single command, which _is_ more efficient if our build system could
leverage this. But -fcallgraph-info is a rather novel flag, so we can't
really rely on it for generally compiling and testing littlefs.

The multi-file output gets in the way when we want an explicitly
separate rule for callgraph-info generation. We can't generate the
callgraph-info without generating the objects files.

This becomes a surprsing issue when parallel building (make -j) is used!
Suddenly we might end up with both the .o and .ci rules writing to .o
files, which creates a really difficult to track down issue of corrupted
.o files.

The temporary solution is to use an order-only prerequisite. This still
ends up building the .o files twice, but it's an acceptable tradeoff for
not requiring the -fcallgraph-info for all builds.
2022-03-20 03:39:18 -05:00
Christopher Haster e4adefd1d7 Fixed spurious encoding error
Using errors=replace in python utf-8 decoding makes these scripts more
resilient to underlying errors, rather than just throwing an unhelpfully
generic decode error.
2022-03-20 03:28:26 -05:00
Christopher Haster 9d54603ce2 Added new scripts to CI results
- Added to GitHub statuses (61 results)

- Reworked generated release table to include these (16 results, only thumb)

These also required a surprisingly large number of other changes:

- Bumbed CI Ubuntu version 18.04 -> 20.04, 22.04 is already on the
  horizon but not usable in GitHub yet

- Manualy upgrade to GCC v10, this is required for the -fcallgraph-info
  flag that scripts/stack.py uses.

- Increased paginated status queries to 100 per-page. If we have more
  statuses than this the status diffs may get much more complicated...

- Forced whitespace in generated release table to always be nbsp. GitHub
  tables get scrunched rather ugly without this, prefering margins to
  readable tables.

- Added limited support for "∞" results, since this is returned by
  ./scripts/stack.py for recursive functions.

As a side-note, this increases the number of statuses reported
per-commit from 6 to 61, so hopefully that doesn't cause any problems...
2022-03-20 03:28:26 -05:00
Christopher Haster 7ea2b515aa A few more tweaks to scripts
- Changed `make summary` to show a one line summary
- Added `make lfs.csv` rule, which is useful for finding more info with
  other scripts
- Fixed small issue in ./scripts/summary.py
- Added *.ci (callgraph) and *.csv (script output) to CI
2022-03-20 03:28:26 -05:00
Christopher Haster 55b3c538d5 Added ./script/summary.py
A full summary of static measurements (code size, stack usage, etc) can now
be found with:

    make summary

This is done through the combination of a new ./scripts/summary.py
script and the ability of existing scripts to merge into existing csv
files, allowing multiple results to be merged either in a pipeline, or
in parallel with a single ./script/summary.py call.

The ./scripts/summary.py script can also be used to quickly compare
different builds or configurations. This is a proper implementation
of a similar but hacky shell script that has already been very useful
for making optimization decisions:

    $ ./scripts/structs.py new.csv -d old.csv --summary
    name (2 added, 0 removed)               code             stack            structs
    TOTAL                                  28648 (-2.7%)      2448               1012

Also some other small tweaks to scripts:

- Removed state saving diff rules. This isn't the most useful way to
  handle comparing changes.

- Added short flags for --summary (-Y) and --files (-F), since these
  are quite often used.
2022-03-20 03:28:26 -05:00
Christopher Haster eb8be9f351 Some improvements to size scripts
- Added -L/--depth argument to show dependencies for scripts/stack.py,
  this replaces calls.py
- Additional internal restructuring to avoid repeated code
- Removed incorrect diff percentage when there is no actual size
- Consistent percentage rendering in test.py
2022-03-20 03:28:21 -05:00
Christopher Haster 50ad2adc96 Added make *-diff rules, quick commands to compare sizes
This required a patch to the --diff flag for the scripts to ignore
a missing file. This enables the useful one liner for making comparisons
with potentially missing previous versions:

    ./scripts/code.py lfs.o -d lfs.o.code.csv -o lfs.o.code.csv

    function (0 added, 0 removed)            old     new    diff
    TOTAL                                  25476   25476      +0

One downside, these previous files are easy to delete as a part of make
clean, which limits their usefulness for comparing configuration
changes...
2022-03-11 14:40:54 -06:00
Christopher Haster 0a2ff3b6ff Added scripts/structs.py for getting sizes of structs
Note this does include internal structs, so this should probably
be limited to informative purposes.
2022-03-11 14:40:54 -06:00
Christopher Haster d7582efec8 Changed script's CSV formats to allow for merging different measurements
- size  -> code_size
- size  -> data_size
- frame -> stack_frame
- limit -> stack_limit
- hits  -> coverage_hits
- count -> coverage_count
2022-03-11 14:40:54 -06:00
Christopher Haster f4c7af76f8 Added scripts/stack.py for viewing stack usage
Note this detects loops (recursion), and renders this as infinity.
Currently littlefs does have a single recursive function and you can see
how this infects the full call graph. Eventually this should be removed.
2022-03-11 14:40:54 -06:00
Christopher Haster 20c58dcbaa Added coverage-sort to scripts/coverage.py
scripts/coverage.py was missed originally because it's not ran as often
as the others. Since it requires run-time info, it's usually only used
in CI.
2022-03-11 14:39:38 -06:00
Christopher Haster f5286abe7a Added scripts/calls.py for viewing the callgraph directly 2022-03-11 14:39:36 -06:00
Christopher Haster 2cdabe810d Split out scripts/code.py into scripts/code.py and scripts/data.py
This is to avoid unexpected script behavior even though data.py should
always return 0 bytes for littlefs. Maybe a check for this should be
added to CI?
2022-03-11 14:39:36 -06:00
Christopher Haster b045436c23 Added size-sort options to scripts/code.py
Now with -s/--sort and -S/--reverse-sort for sorting the functions by
size.

You may wonder why add reverse-sort, since its utility doesn't seem
worth the cost to implement (these are just helper scripts after all),
the reason is that reverse-sort is quite useful on the command-line,
where scrollback may be truncated, and you only care about the larger
entries.

Outside of the command-line, normal sort is prefered.

Fortunately the difference is just the sign in the sort key.

Note this conflicts with the short --summary flag, so that has been
removed.
2022-03-11 14:36:23 -06:00
Christopher Haster ead50807f1 Merge pull request #565 from tniessen/fix-link-to-test-bd
Fix link to test block device
v2.4.1
2021-06-12 12:35:34 -05:00
Christopher Haster 2f7596811d Merge pull request #529 from yamt/macos-make-test
scripts/test.py: Fix infinite busy loops on macOS
2021-06-12 12:35:25 -05:00
Tobias Nießen 1e423bae58 Fix link to test block device 2021-06-09 21:04:50 +02:00
YAMAMOTO Takashi 3bee4d9a19 scripts/test.py: Fix infinite busy loops on macOS
I confirmed that the same number of tests are run
with "make test" on:

    * Ubuntu with and without this change
    * macOS with this change

>   ====== results ======
>   tests passed 817/817 (100.00%)
>   tests failed 0/817 (0.00%)
2021-02-22 14:42:10 +09:00
Christopher Haster 1863dc7883 Merge pull request #519 from littlefs-project/devel
Minor release: v2.4
v2.4.0
2021-01-19 18:50:34 -06:00
Christopher Haster 3d4e4f2085 Bumped minor version to v2.4 2021-01-18 20:23:54 -06:00
Christopher Haster a2c744c8f8 Merge pull request #516 from littlefs-project/ci-revamp
Adopt GitHub Actions, bring in a number of script/Makefile improvements
2021-01-18 18:38:42 -06:00
Christopher Haster c0cc0a417e Enabled overriding of LFS_ASSERT/TRACE/DEBUG/etc
This is useful for testing the new erroring assert behavior in CI.
Asserts do not error by default, so this macro needs to be overriden.

It is possible to test this behavior using the existing option of
overriding lfs_util.h with a custom file, by using a small sed
one-line script. But this is much simpler.

This does raise the question if more of the configuration options in
lfs_util.h should be opened up for function-like macro overrides.
2021-01-18 14:01:53 -06:00
Christopher Haster bca64d76cf Merge branch 'devel' into ci-revamp
Needed to bring in new "error-asserts" configuration
2021-01-18 12:23:25 -06:00
Christopher Haster cab1d6cca6 Merge pull request #514 from mon/feature/assert_early_return
lfs_fs_preporphans: return int to alllow graceful LFS_ASSERT
2021-01-18 11:53:47 -06:00
Will c9eed1f181 Add test to ensure asserts can return 2021-01-18 11:50:39 -06:00
Will e7e4b352bd lfs_fs_preporphans ret int for graceful LFS_ASSERT 2021-01-18 11:50:33 -06:00
Christopher Haster 9449ef4be4 Merge pull request #511 from embeddedt/fix_lseek
Skip flushing file if lfs_file_rawseek() doesn't change position
2021-01-18 11:47:56 -06:00
Christopher Haster cfe779fc08 Merge pull request #508 from littlefs-project/fix-sanity-check
Moved sanity check in lfs_format after compaction
2021-01-18 11:47:23 -06:00
Christopher Haster 0db6466984 Merge pull request #502 from mon/feature/meta_limits
Add metadata_max config to help performance on devices with large blocks
2021-01-18 11:45:34 -06:00
Christopher Haster 21488d9e06 Fixed incorrect documentation in test.py
The argparse documented an outdated format, and was off by 1.

Found by sender6
2021-01-18 11:41:51 -06:00
Christopher Haster 10a08833c6 Moved lfs_mdir_isopen behind LFS_NO_ASSERT
lfs_mdir_isopen goes unused if asserts are disabled, and this caused an
"unused function" warning on Clang (curiously not on GCC since the
function was static inline, commonly used for header-only functions).

Also removed "inline" from the lfs_mdir_* functions as these involve
linked-list operations and really shouldn't be inlined. And since they
are static, inlining should occur automatically if there is a benefit.

Found by dpgeorge
2021-01-18 11:41:18 -06:00
Christopher Haster 47d6b2fcf3 Removed unnecessary truncate condition thanks to new seek optimization 2021-01-11 00:14:34 -06:00
Christopher Haster 745d98cde0 Fixed lfs_file_truncate issue where internal state may not be flushed
This was caused by the new lfs_file_rawseek optimization that can skip
flushing when calculated file->pos is unchanged combined with an
implicit expectation in lfs_file_truncate that lfs_file_rawseek
unconditionally sets file->pos.

Because of this assumption, lfs_file_truncate could leave file->pos in
an outdated state while changing the internal file metadata. Humorously,
this was always gauranteed to trigger the skip in lfs_file_rawseek when
we try to restore the file->pos, leaving the file->cache used to do the
CTZ skip-list lookup in a potentially bad state.

The easiest fix is to just update file->pos correctly. Note we don't
want to explicitly flush since we can leverage the same noop
optimization if we truncate to the file position. Which I've added a
test for.
2021-01-11 00:14:34 -06:00
Themba Dube 3216b07c3b Use lfs_file_rawsize to calculate LFS_SEEK_END position 2021-01-11 00:14:30 -06:00
Christopher Haster 6592719d28 Removed .travis.yml
Now that it's been replaced by GitHub workflows (in .github/workflows)
2021-01-10 13:20:14 -06:00
Christopher Haster c9110617b3 Added post-release script, cleaned up workflows
This helps an outstanding maintainer annoyance: updating dependencies to
bring in new versions on each littlefs release.

But instead of adding a bunch of scripts to the tail end of the release
workflow, the post-release script just triggers a single
"repository_dispatch" event in the newly created littlefs.post-release
repo. From there any number of post-release workflows can be run.

This indirection should let the post-release scripts move much quicker
than littlefs itself, which helps offset how fragile these sort of scripts
are.

---

Also finished cleaning up the workflows now that they are mostly
working.
2021-01-10 13:20:11 -06:00
Christopher Haster 104d65113d Reduced build sources to just the core littlefs
Currently this is just lfs.c and lfs_util.c. Previously this included
the block devices, but this meant all of the scripts needed to
explicitly deselect the block devices to avoid reporting build
size/coverage info on them.

Note that test.py still explicitly adds the block devices for compiling
tests, which is their main purpose. Humorously this means the block
devices will probably be compiled into most builds in this repo anyways.
2021-01-10 04:03:16 -06:00
Christopher Haster 6d3e4ac33e Brought over the release workflow
This is pretty much a cleaned up version of the release script that ran
on Travis.

This biggest change is that now the release script also collecs the
build results into a table as part of the change notes, which is a nice
addition.
2021-01-10 04:03:13 -06:00
Christopher Haster 9d6546071b Fixed a recompilation issue in CI, tweaked coverage.py a bit more
This was lost in the Travis -> GitHub transition, in serializing some of
the jobs, I missed that we need to clean between tests with different
geometry configurations. Otherwise we end up running outdated binaries,
which explains some of the weird test behavior we were seeing.

Also tweaked a few script things:
- Better subprocess error reporting (dump stderr on failure)
- Fixed a BUILDDIR rule issue in test.py
- Changed test-not-run status to None instead of undefined
2021-01-10 03:21:28 -06:00
Christopher Haster b84fb6bcc5 Added BUILDDIR, a bit of script reworking
Now littlefs's Makefile can work with a custom build directory
for compilation output. Just set the BUILDDIR variable and the Makefile
will take care of the rest.

make BUILDDIR=build size

This makes it very easy to compare builds with different compile-time
configurations or different cross-compilers.

This meant most of code.py's build isolation is no longer needed,
so revisted the scripts and cleaned/tweaked a number of things.

Also bought code.py in line with coverage.py, fixing some of the
inconsistencies that were created while developing these scripts.

One change to note was removing the inline measuring logic, I realized
this feature is unnecessary thanks to GCC's -fkeep-static-functions and
-fno-inline flags.
2021-01-10 03:21:21 -06:00
Christopher Haster 887f3660ed Switched to lcov for coverage collection, greatly simplified coverage.py
Since we already have fairly complicated scriptts, I figured it wouldn't
be too hard to use the gcov tools and directly parse their output. Boy
was I wrong.

The gcov intermediary format is a bit of a mess. In version 5.4, a
text-based intermediary format is written to a single .gcov file per
executable. This changed sometime before version 7.5, when it started
writing separate .gcov files per .o files. And in version 9 this
intermediary format has been entirely replaced with an incompatible json
format!

Ironically, this means the internal-only .gcda/.gcno binary format has
actually been more stable than the intermediary format.

Also there's no way to avoid temporary .gcov files generated in the
project root, which risks messing with how test.py runs parallel tests.
Fortunately this looks like it will be fixed in gcov version 9.

---

Ended up switching to lcov, which was the right way to go. lcov handles
all of the gcov parsing, provides an easily parsable output, and even
provides a set of higher-level commands to manage coverage collection
from different runs.

Since this is all provided by lcov, was able to simplify coverage.py
quite a bit. Now it just parses the .info files output by lcov.
2021-01-10 02:21:33 -06:00
Christopher Haster eeeceb9e30 Added coverage.py, and optional coverage info to test.py
Now coverage information can be collected if you provide the --coverage
to test.py. Internally this uses GCC's gcov instrumentation along with a
new script, coverage.py, to parse *.gcov files.

The main use for this is finding coverage info during CI runs. There's a
risk that the instrumentation may make it more difficult to debug, so I
decided to not make coverage collection enabled by default.
2021-01-10 02:12:45 -06:00
Christopher Haster b2235e956d Added GitHub workflows to run tests
Mostly taken from .travis.yml, biggest changes were around how to get
the status updates to work.

We can't use a token on PRs the same way we could in Travis, so instead
we use a second workflow that checks every pull request for "status"
artifacts, and create the actual statuses in the "workflow_run" event,
where we have full access to repo secrets.
2021-01-09 23:42:49 -06:00
Themba Dube 6bb4043154 Skip flushing file if lfs_file_rawseek() doesn't change position 2020-12-24 14:05:46 -05:00
Christopher Haster 2b804537b0 Moved sanity check in lfs_format after compaction
After a bit of tweaking in 9dde5c7 to write out all superblocks
during lfs_format, additional writes were added after the sanity
checking normally done at the end.

This turned out to be a problem when porting littlefs, as it makes it
easy for addressing issues to not get caught during lfs_format.

Found by marekr, tristanclare94, and mjs513
2020-12-22 11:47:48 -06:00
Christopher Haster d804c2d3b7 Added scripts/code_size.py, for more in-depth code-size reporting
Inspired by Linux's Bloat-O-Meter, code_size.py wraps nm to provide
function-level code size, and supports detailed comparison between
different builds.

One difference is that code_size.py invokes littlefs's build system
similarly to test.py, creating a duplicate build in the "sizes"
directory. This makes it easy to monitor a cross-compiled build size
while simultaneously testing on the host machine.
2020-12-19 18:49:57 -06:00
Will 37f4de2976 Remove inline_files_max and lfs_t entry for metadata_max 2020-12-18 13:05:20 +10:00