1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include "_debug.h" 28 #include "msg.h" 29 #include "libld.h" 30 31 static const char * 32 fmt_human_units(size_t bytes, char *buf, size_t bufsize) 33 { 34 static int unit_arr[] = { 'K', 'M', 'G', 'T' }; 35 36 int i, unit_ch; 37 size_t unit_bytes = bytes; 38 39 /* Convert to human readable units */ 40 for (i = 0; i < sizeof (unit_arr) / sizeof (unit_arr[0]); i++) { 41 if (unit_bytes < 1024) 42 break; 43 unit_ch = unit_arr[i]; 44 unit_bytes /= 1024; 45 } 46 if (unit_bytes == bytes) 47 buf[0] = '\0'; 48 else 49 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_MEMUNIT), 50 EC_XWORD(unit_bytes), unit_ch); 51 52 return (buf); 53 } 54 55 /* 56 * Generate a relocation cache statistics line for the active or 57 * output relocation cache. 58 * 59 * entry: 60 * ofl - output file descriptor 61 * alp - One of ofl->ofl_actrels or ofl->ofl_outrels. 62 */ 63 static void 64 rel_cache_statistics(Ofl_desc *ofl, const char *title, APlist *alp) 65 { 66 Lm_list *lml = ofl->ofl_lml; 67 size_t desc_cnt = 0, desc_used = 0, bytes; 68 Aliste idx; 69 Rel_cachebuf *rcp; 70 char unit_buf[CONV_INV_BUFSIZE + 10]; 71 72 /* Sum the total memory allocated across all the buffers */ 73 for (APLIST_TRAVERSE(alp, idx, rcp)) { 74 desc_cnt += rcp->rc_end - rcp->rc_arr; 75 desc_used += rcp->rc_free - rcp->rc_arr; 76 } 77 bytes = desc_cnt * sizeof (Rel_desc); 78 79 dbg_print(lml, MSG_INTL(MSG_STATS_REL_CACHE), title, 80 EC_WORD(aplist_nitems(alp)), 81 EC_XWORD(desc_used), EC_XWORD(desc_cnt), 82 (desc_cnt == 0) ? 100 : EC_WORD((desc_used * 100) / desc_cnt), 83 EC_XWORD(bytes), 84 fmt_human_units(bytes, unit_buf, sizeof (unit_buf))); 85 } 86 87 88 /* 89 * Generate a statistics line for the auxiliary relocation descriptor cache. 90 * 91 * entry: 92 * ofl - output file descriptor 93 */ 94 static void 95 rel_aux_cache_statistics(Ofl_desc *ofl) 96 { 97 Rel_aux_cachebuf *racp; 98 Lm_list *lml = ofl->ofl_lml; 99 size_t desc_cnt = 0, desc_used = 0, bytes; 100 Aliste idx; 101 char unit_buf[CONV_INV_BUFSIZE + 10]; 102 103 /* Sum the total memory allocated across all the buffers */ 104 for (APLIST_TRAVERSE(ofl->ofl_relaux, idx, racp)) { 105 desc_cnt += racp->rac_end - racp->rac_arr; 106 desc_used += racp->rac_free - racp->rac_arr; 107 } 108 bytes = desc_cnt * sizeof (Rel_desc); 109 110 dbg_print(lml, MSG_INTL(MSG_STATS_REL_ACACHE), 111 EC_WORD(aplist_nitems(ofl->ofl_relaux)), 112 EC_XWORD(desc_used), EC_XWORD(desc_cnt), 113 (desc_cnt == 0) ? 100 : EC_WORD((desc_used * 100) / desc_cnt), 114 EC_XWORD(bytes), 115 fmt_human_units(bytes, unit_buf, sizeof (unit_buf))); 116 } 117 118 119 void 120 Dbg_statistics_ld(Ofl_desc *ofl) 121 { 122 Lm_list *lml = ofl->ofl_lml; 123 124 if (DBG_NOTCLASS(DBG_C_STATS)) 125 return; 126 127 Dbg_util_nl(lml, DBG_NL_STD); 128 dbg_print(lml, MSG_INTL(MSG_STATS_GENERAL)); 129 130 if (ofl->ofl_objscnt || ofl->ofl_soscnt || ofl->ofl_arscnt) { 131 dbg_print(lml, MSG_INTL(MSG_STATS_FILES), 132 EC_XWORD(ofl->ofl_objscnt), EC_XWORD(ofl->ofl_soscnt), 133 EC_XWORD(ofl->ofl_arscnt)); 134 } 135 136 if (ofl->ofl_locscnt || ofl->ofl_globcnt) { 137 dbg_print(lml, MSG_INTL(MSG_STATS_SYMBOLS_OUT), 138 EC_XWORD(ofl->ofl_globcnt), EC_XWORD(ofl->ofl_locscnt)); 139 } 140 if (ofl->ofl_entercnt || ofl->ofl_scopecnt || ofl->ofl_elimcnt) { 141 dbg_print(lml, MSG_INTL(MSG_STATS_SYMBOLS_IN), 142 EC_XWORD(ofl->ofl_entercnt), EC_XWORD(ofl->ofl_scopecnt), 143 EC_XWORD(ofl->ofl_elimcnt)); 144 } 145 146 dbg_print(lml, MSG_INTL(MSG_STATS_REL_OUT), 147 EC_XWORD(ofl->ofl_outrels.rc_cnt)); 148 149 dbg_print(lml, MSG_INTL(MSG_STATS_REL_IN), 150 EC_XWORD(ofl->ofl_entrelscnt), EC_XWORD(ofl->ofl_actrels.rc_cnt)); 151 152 dbg_print(lml, MSG_INTL(MSG_STATS_REL_TICACHE)); 153 rel_cache_statistics(ofl, MSG_INTL(MSG_STATS_REL_TIOUT), 154 ofl->ofl_outrels.rc_list); 155 rel_cache_statistics(ofl, MSG_INTL(MSG_STATS_REL_TIACT), 156 ofl->ofl_actrels.rc_list); 157 rel_aux_cache_statistics(ofl); 158 } 159 160 void 161 Dbg_statistics_ar(Ofl_desc *ofl) 162 { 163 Aliste idx; 164 Ar_desc *adp; 165 Elf_Arsym *arsym; 166 Ar_aux *aux; 167 Lm_list *lml = ofl->ofl_lml; 168 169 if (DBG_NOTCLASS(DBG_C_STATS | DBG_C_UNUSED)) 170 return; 171 172 Dbg_util_nl(lml, DBG_NL_STD); 173 for (APLIST_TRAVERSE(ofl->ofl_ars, idx, adp)) { 174 size_t poffset = 0; 175 uint_t count = 0, used = 0; 176 177 if ((adp->ad_flags & FLG_ARD_EXTRACT) == 0) { 178 Dbg_unused_file(lml, adp->ad_name, 0, 0); 179 continue; 180 } 181 182 if (DBG_NOTCLASS(DBG_C_STATS)) 183 continue; 184 185 arsym = adp->ad_start; 186 aux = adp->ad_aux; 187 while ((arsym != NULL) && (arsym->as_off != 0)) { 188 /* 189 * Assume that symbols from the same member file are 190 * adjacent within the archive symbol table. 191 */ 192 if (poffset != arsym->as_off) { 193 count++; 194 poffset = arsym->as_off; 195 if (aux->au_mem == FLG_ARMEM_PROC) 196 used++; 197 } 198 aux++, arsym++; 199 } 200 if ((count == 0) || (used == 0)) 201 continue; 202 203 dbg_print(lml, MSG_INTL(MSG_STATS_AR), adp->ad_name, count, 204 used, ((used * 100) / count)); 205 } 206 Dbg_util_nl(lml, DBG_NL_STD); 207 } 208