Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 1 | /* |
Rickard Bolin | 899500d | 2023-02-10 11:55:41 +0000 | [diff] [blame] | 2 | * SPDX-FileCopyrightText: Copyright 2020, 2022 Arm Limited and/or its affiliates <open-source-office@arm.com> |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the License); you may |
| 7 | * not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
| 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | |
| 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <stdint.h> |
| 22 | #include <stdbool.h> |
| 23 | #include <string.h> |
| 24 | #include <assert.h> |
| 25 | #include <math.h> |
| 26 | #include <getopt.h> |
| 27 | #include <stdarg.h> |
| 28 | #include "mlw_encode.h" |
| 29 | #include "mlw_decode.h" |
| 30 | |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 31 | #define UNCHECKED(call) (void)call |
| 32 | |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 33 | static void fatal_error(const char *format, ...) { |
| 34 | va_list ap; |
| 35 | va_start (ap, format); |
| 36 | vfprintf(stderr, format, ap); |
| 37 | va_end(ap); |
| 38 | exit(1); |
| 39 | } |
| 40 | |
| 41 | static void print_usage(void) { |
| 42 | printf("Usage:\n"); |
| 43 | printf(" Encode: ./mlw_codec [<options>] [-o <outfile.mlw>] infiles.bin\n"); |
| 44 | printf(" Decode: ./mlw_codec [<options>] -d [-o <outfile.bin>] infiles.mlw\n"); |
| 45 | printf("\n"); |
| 46 | printf("Options:\n"); |
| 47 | printf(" -w The uncompressed weight file is an int16_t (word) stream.\n"); |
| 48 | printf(" This is to support 9bit signed weights. Little endian is assuemd.\n"); |
| 49 | printf(" The default format is int8_t (byte) stream (if -w is not specified)\n"); |
| 50 | printf("\n"); |
| 51 | } |
| 52 | |
| 53 | // Read file into allocated buffer. Return length in bytes. |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 54 | static size_t read_file( FILE *f, uint8_t **buf) { |
| 55 | size_t rsize = 0; |
| 56 | UNCHECKED(fseek(f, 0, SEEK_END)); |
| 57 | long size = ftell(f); |
| 58 | size = size < 0 ? 0 : size; |
| 59 | UNCHECKED(fseek(f, 0, SEEK_SET)); |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 60 | *buf = malloc(size); |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 61 | if (*buf) |
| 62 | { |
| 63 | rsize = fread(*buf, 1, size, f); |
| 64 | assert(rsize==size); |
| 65 | } |
| 66 | UNCHECKED(fclose(f)); |
| 67 | return rsize; |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | |
| 71 | #define MAX_INFILES 1000 |
| 72 | |
| 73 | int main(int argc, char *argv[]) |
| 74 | { |
| 75 | int c, decode=0, inbuf_size, outbuf_size; |
| 76 | char *infile_name[MAX_INFILES], *outfile_name=0; |
| 77 | uint8_t *inbuf=0, *outbuf=0; |
| 78 | FILE *infile, *outfile=0; |
| 79 | int verbose=0, infile_idx=0; |
| 80 | int int16_format=0; |
| 81 | |
| 82 | if (argc==1) { |
| 83 | print_usage(); |
| 84 | exit(1); |
| 85 | } |
| 86 | |
| 87 | // Parse command line options |
| 88 | while( optind < argc) { |
| 89 | // Parse options |
| 90 | while ((c = getopt (argc, argv, "di:o:v:w?")) != -1) { |
| 91 | switch (c) { |
| 92 | case 'd': |
| 93 | decode=1; |
| 94 | break; |
| 95 | case 'i': |
| 96 | assert(infile_idx<MAX_INFILES); |
| 97 | infile_name[infile_idx++]=optarg; |
| 98 | break; |
| 99 | case 'o': |
| 100 | outfile_name=optarg; |
| 101 | break; |
| 102 | case 'v': |
| 103 | verbose=atoi(optarg); |
| 104 | break; |
| 105 | case 'w': |
| 106 | int16_format=1; |
| 107 | break; |
| 108 | case '?': |
| 109 | print_usage(); |
| 110 | exit(0); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | if (optind<argc) { |
| 115 | assert(infile_idx<MAX_INFILES); |
| 116 | infile_name[infile_idx++]=argv[optind]; |
| 117 | optind++; |
| 118 | |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | if (outfile_name) { |
| 123 | outfile=fopen(outfile_name, "wb"); |
| 124 | if (!outfile) |
| 125 | fatal_error("ERROR: cannot open outfile %s\n", outfile_name); |
| 126 | } |
| 127 | |
| 128 | // Loop over input files |
| 129 | int nbr_of_infiles=infile_idx; |
| 130 | for(infile_idx=0; infile_idx<nbr_of_infiles; infile_idx++) { |
| 131 | infile=fopen(infile_name[infile_idx], "rb"); |
| 132 | if (!infile) |
| 133 | fatal_error("ERROR: cannot open infile %s\n", infile_name[infile_idx]); |
| 134 | |
| 135 | // Read infile to buffer |
| 136 | inbuf_size = read_file(infile, &inbuf); |
| 137 | |
| 138 | if (!decode) { |
| 139 | // Encode |
Michael McGeagh | d5cf765 | 2020-12-03 13:53:56 +0000 | [diff] [blame] | 140 | int i, n = int16_format ? inbuf_size/(int)sizeof(int16_t) : inbuf_size; |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 141 | int16_t *weights = malloc( n * sizeof(int16_t) ); |
| 142 | for(i=0; i<n; i++) { |
| 143 | weights[i] = int16_format ? ((int16_t*)inbuf)[i] : ((int8_t*)inbuf)[i]; |
| 144 | } |
| 145 | outbuf_size = mlw_encode( weights, n, &outbuf, verbose); |
| 146 | free(weights); |
| 147 | printf("Input size %d output size %d bpw %4.2f\n", n, outbuf_size, outbuf_size*8.0/n); |
| 148 | } else { |
| 149 | // Decode |
| 150 | int i, n; |
| 151 | int16_t *weights; |
| 152 | n = mlw_decode( inbuf, inbuf_size, &weights, verbose); |
Michael McGeagh | d5cf765 | 2020-12-03 13:53:56 +0000 | [diff] [blame] | 153 | outbuf_size = int16_format ? n*(int)sizeof(int16_t) : n; |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 154 | outbuf = malloc( outbuf_size ); |
| 155 | assert(outbuf); |
| 156 | for(i=0; i<n; i++) { |
| 157 | if (int16_format) |
| 158 | ((int16_t*)outbuf)[i] = weights[i]; |
| 159 | else |
| 160 | outbuf[i] = weights[i]; |
| 161 | } |
| 162 | free(weights); |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 163 | printf("Input size %d output size %d bpw %4.2f\n", inbuf_size, n, n ? inbuf_size*8.0/n : 0); |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 164 | |
| 165 | } |
| 166 | |
| 167 | if (outfile) { |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 168 | UNCHECKED(fwrite(outbuf, 1, outbuf_size, outfile)); |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | if (inbuf) |
| 172 | free(inbuf); |
| 173 | if (outbuf) |
| 174 | free(outbuf); |
| 175 | } |
| 176 | |
| 177 | if (outfile) { |
Fredrik Svedberg | db947e4 | 2022-11-22 15:47:24 +0100 | [diff] [blame] | 178 | UNCHECKED(fclose(outfile)); |
Tim Hall | 79d07d2 | 2020-04-27 18:20:16 +0100 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | return 0; |
| 182 | } |